Compare commits
27 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
6f0395538b | ||
|
b9f1ff3c77 | ||
|
a77af4c5e9 | ||
|
fbcf802fbc | ||
|
c3c41fa4bb | ||
|
356e480bf5 | ||
|
8e119a1e96 | ||
|
e05bf90af6 | ||
|
66f16f4392 | ||
|
729ff5337c | ||
|
2492e7e808 | ||
|
36172ab43b | ||
|
4d69286a9c | ||
|
1529e6cf0d | ||
|
f468db7602 | ||
|
c5f1d1749a | ||
|
7dd69f2d0e | ||
|
c646638680 | ||
|
65f2a82b97 | ||
|
93dd6d525a | ||
|
96d4ad952c | ||
|
6a07f80b76 | ||
|
22214ac664 | ||
|
45e520a27c | ||
|
5b5810a46a | ||
|
619ac86bd0 | ||
|
7a1ab71c73 |
@@ -7,5 +7,8 @@
|
|||||||
|
|
||||||
int Msb { get; }
|
int Msb { get; }
|
||||||
int Lsb { get; }
|
int Lsb { get; }
|
||||||
|
|
||||||
|
int SourceMask => (int)(0xFFFFFFFF >> (31 - Msb));
|
||||||
|
int DestMask => SourceMask & (int)(0xFFFFFFFF << Lsb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
7
ARMeilleure/Decoders/IOpCode32AluImm16.cs
Normal file
7
ARMeilleure/Decoders/IOpCode32AluImm16.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
interface IOpCode32AluImm16 : IOpCode32Alu
|
||||||
|
{
|
||||||
|
int Immediate { get; }
|
||||||
|
}
|
||||||
|
}
|
11
ARMeilleure/Decoders/IOpCode32AluMla.cs
Normal file
11
ARMeilleure/Decoders/IOpCode32AluMla.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
interface IOpCode32AluMla : IOpCode32AluReg
|
||||||
|
{
|
||||||
|
int Ra { get; }
|
||||||
|
|
||||||
|
bool NHigh { get; }
|
||||||
|
bool MHigh { get; }
|
||||||
|
bool R { get; }
|
||||||
|
}
|
||||||
|
}
|
13
ARMeilleure/Decoders/IOpCode32AluUmull.cs
Normal file
13
ARMeilleure/Decoders/IOpCode32AluUmull.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
interface IOpCode32AluUmull : IOpCode32, IOpCode32HasSetFlags
|
||||||
|
{
|
||||||
|
int RdLo { get; }
|
||||||
|
int RdHi { get; }
|
||||||
|
int Rn { get; }
|
||||||
|
int Rm { get; }
|
||||||
|
|
||||||
|
bool NHigh { get; }
|
||||||
|
bool MHigh { get; }
|
||||||
|
}
|
||||||
|
}
|
@@ -13,16 +13,13 @@ namespace ARMeilleure.Decoders
|
|||||||
Cond = (Condition)((uint)opCode >> 28);
|
Cond = (Condition)((uint)opCode >> 28);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsThumb()
|
public bool IsThumb { get; protected init; } = false;
|
||||||
{
|
|
||||||
return this is OpCodeT16 || this is OpCodeT32;
|
|
||||||
}
|
|
||||||
|
|
||||||
public uint GetPc()
|
public uint GetPc()
|
||||||
{
|
{
|
||||||
// Due to backwards compatibility and legacy behavior of ARMv4 CPUs pipeline,
|
// Due to backwards compatibility and legacy behavior of ARMv4 CPUs pipeline,
|
||||||
// the PC actually points 2 instructions ahead.
|
// the PC actually points 2 instructions ahead.
|
||||||
if (IsThumb())
|
if (IsThumb)
|
||||||
{
|
{
|
||||||
// PC is ahead by 4 in thumb mode whether or not the current instruction
|
// PC is ahead by 4 in thumb mode whether or not the current instruction
|
||||||
// is 16 or 32 bit.
|
// is 16 or 32 bit.
|
||||||
|
@@ -6,12 +6,8 @@
|
|||||||
public int Rn { get; }
|
public int Rn { get; }
|
||||||
|
|
||||||
public int Msb { get; }
|
public int Msb { get; }
|
||||||
|
|
||||||
public int Lsb { get; }
|
public int Lsb { get; }
|
||||||
|
|
||||||
public int SourceMask => (int)(0xFFFFFFFF >> (31 - Msb));
|
|
||||||
public int DestMask => SourceMask & (int)(0xFFFFFFFF << Lsb);
|
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32AluBf(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32AluBf(inst, address, opCode);
|
||||||
|
|
||||||
public OpCode32AluBf(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32AluBf(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
namespace ARMeilleure.Decoders
|
namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCode32AluImm16 : OpCode32Alu
|
class OpCode32AluImm16 : OpCode32Alu, IOpCode32AluImm16
|
||||||
{
|
{
|
||||||
public int Immediate { get; }
|
public int Immediate { get; }
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
namespace ARMeilleure.Decoders
|
namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCode32AluMla : OpCode32, IOpCode32AluReg
|
class OpCode32AluMla : OpCode32, IOpCode32AluMla
|
||||||
{
|
{
|
||||||
public int Rn { get; }
|
public int Rn { get; }
|
||||||
public int Rm { get; }
|
public int Rm { get; }
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
namespace ARMeilleure.Decoders
|
namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCode32AluUmull : OpCode32, IOpCode32HasSetFlags
|
class OpCode32AluUmull : OpCode32, IOpCode32AluUmull
|
||||||
{
|
{
|
||||||
public int RdLo { get; }
|
public int RdLo { get; }
|
||||||
public int RdHi { get; }
|
public int RdHi { get; }
|
||||||
@@ -11,7 +11,6 @@
|
|||||||
public bool MHigh { get; }
|
public bool MHigh { get; }
|
||||||
|
|
||||||
public bool? SetFlags { get; }
|
public bool? SetFlags { get; }
|
||||||
public DataOp DataOp { get; }
|
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32AluUmull(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32AluUmull(inst, address, opCode);
|
||||||
|
|
||||||
@@ -26,7 +25,6 @@
|
|||||||
MHigh = ((opCode >> 6) & 0x1) == 1;
|
MHigh = ((opCode >> 6) & 0x1) == 1;
|
||||||
|
|
||||||
SetFlags = ((opCode >> 20) & 0x1) != 0;
|
SetFlags = ((opCode >> 20) & 0x1) != 0;
|
||||||
DataOp = DataOp.Arithmetic;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -7,14 +7,15 @@
|
|||||||
public bool F { get; protected set; }
|
public bool F { get; protected set; }
|
||||||
public bool U { get; }
|
public bool U { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32Simd(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32Simd(inst, address, opCode, false);
|
||||||
|
public static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32Simd(inst, address, opCode, true);
|
||||||
|
|
||||||
public OpCode32Simd(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32Simd(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
|
||||||
{
|
{
|
||||||
Size = (opCode >> 20) & 0x3;
|
Size = (opCode >> 20) & 0x3;
|
||||||
Q = ((opCode >> 6) & 0x1) != 0;
|
Q = ((opCode >> 6) & 0x1) != 0;
|
||||||
F = ((opCode >> 10) & 0x1) != 0;
|
F = ((opCode >> 10) & 0x1) != 0;
|
||||||
U = ((opCode >> 24) & 0x1) != 0;
|
U = ((opCode >> (isThumb ? 28 : 24)) & 0x1) != 0;
|
||||||
Opc = (opCode >> 7) & 0x3;
|
Opc = (opCode >> 7) & 0x3;
|
||||||
|
|
||||||
RegisterSize = Q ? RegisterSize.Simd128 : RegisterSize.Simd64;
|
RegisterSize = Q ? RegisterSize.Simd128 : RegisterSize.Simd64;
|
||||||
|
@@ -47,6 +47,9 @@ namespace ARMeilleure.Decoders
|
|||||||
throw new InvalidOperationException();
|
throw new InvalidOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public OpCode32SimdBase(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) { }
|
protected OpCode32SimdBase(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
IsThumb = isThumb;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,9 +5,10 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
class OpCode32SimdBinary : OpCode32SimdReg
|
class OpCode32SimdBinary : OpCode32SimdReg
|
||||||
{
|
{
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdBinary(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdBinary(inst, address, opCode, false);
|
||||||
|
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdBinary(inst, address, opCode, true);
|
||||||
|
|
||||||
public OpCode32SimdBinary(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32SimdBinary(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
|
||||||
{
|
{
|
||||||
Size = 3;
|
Size = 3;
|
||||||
|
|
||||||
|
@@ -2,9 +2,10 @@
|
|||||||
{
|
{
|
||||||
class OpCode32SimdCmpZ : OpCode32Simd
|
class OpCode32SimdCmpZ : OpCode32Simd
|
||||||
{
|
{
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdCmpZ(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdCmpZ(inst, address, opCode, false);
|
||||||
|
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdCmpZ(inst, address, opCode, true);
|
||||||
|
|
||||||
public OpCode32SimdCmpZ(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32SimdCmpZ(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
|
||||||
{
|
{
|
||||||
Size = (opCode >> 18) & 0x3;
|
Size = (opCode >> 18) & 0x3;
|
||||||
|
|
||||||
|
@@ -2,9 +2,10 @@
|
|||||||
{
|
{
|
||||||
class OpCode32SimdCvtFI : OpCode32SimdS
|
class OpCode32SimdCvtFI : OpCode32SimdS
|
||||||
{
|
{
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdCvtFI(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdCvtFI(inst, address, opCode, false);
|
||||||
|
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdCvtFI(inst, address, opCode, true);
|
||||||
|
|
||||||
public OpCode32SimdCvtFI(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32SimdCvtFI(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
|
||||||
{
|
{
|
||||||
Opc = (opCode >> 7) & 0x1;
|
Opc = (opCode >> 7) & 0x1;
|
||||||
|
|
||||||
|
@@ -4,9 +4,10 @@
|
|||||||
{
|
{
|
||||||
public int Index { get; }
|
public int Index { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdDupElem(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdDupElem(inst, address, opCode, false);
|
||||||
|
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdDupElem(inst, address, opCode, true);
|
||||||
|
|
||||||
public OpCode32SimdDupElem(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32SimdDupElem(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
|
||||||
{
|
{
|
||||||
var opc = (opCode >> 16) & 0xf;
|
var opc = (opCode >> 16) & 0xf;
|
||||||
|
|
||||||
|
@@ -7,10 +7,13 @@
|
|||||||
public int Rt { get; }
|
public int Rt { get; }
|
||||||
public bool Q { get; }
|
public bool Q { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdDupGP(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdDupGP(inst, address, opCode, false);
|
||||||
|
public static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdDupGP(inst, address, opCode, true);
|
||||||
|
|
||||||
public OpCode32SimdDupGP(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32SimdDupGP(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
|
IsThumb = isThumb;
|
||||||
|
|
||||||
Size = 2 - (((opCode >> 21) & 0x2) | ((opCode >> 5) & 0x1)); // B:E - 0 for 32, 16 then 8.
|
Size = 2 - (((opCode >> 21) & 0x2) | ((opCode >> 5) & 0x1)); // B:E - 0 for 32, 16 then 8.
|
||||||
if (Size == -1)
|
if (Size == -1)
|
||||||
{
|
{
|
||||||
|
@@ -4,9 +4,10 @@
|
|||||||
{
|
{
|
||||||
public int Immediate { get; }
|
public int Immediate { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdExt(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdExt(inst, address, opCode, false);
|
||||||
|
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdExt(inst, address, opCode, true);
|
||||||
|
|
||||||
public OpCode32SimdExt(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32SimdExt(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
|
||||||
{
|
{
|
||||||
Immediate = (opCode >> 8) & 0xf;
|
Immediate = (opCode >> 8) & 0xf;
|
||||||
Size = 0;
|
Size = 0;
|
||||||
|
@@ -6,9 +6,10 @@
|
|||||||
public long Immediate { get; }
|
public long Immediate { get; }
|
||||||
public int Elems => GetBytesCount() >> Size;
|
public int Elems => GetBytesCount() >> Size;
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdImm(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdImm(inst, address, opCode, false);
|
||||||
|
public static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdImm(inst, address, opCode, true);
|
||||||
|
|
||||||
public OpCode32SimdImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32SimdImm(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
|
||||||
{
|
{
|
||||||
Vd = (opCode >> 12) & 0xf;
|
Vd = (opCode >> 12) & 0xf;
|
||||||
Vd |= (opCode >> 18) & 0x10;
|
Vd |= (opCode >> 18) & 0x10;
|
||||||
@@ -22,7 +23,7 @@
|
|||||||
|
|
||||||
imm = ((uint)opCode >> 0) & 0xf;
|
imm = ((uint)opCode >> 0) & 0xf;
|
||||||
imm |= ((uint)opCode >> 12) & 0x70;
|
imm |= ((uint)opCode >> 12) & 0x70;
|
||||||
imm |= ((uint)opCode >> 17) & 0x80;
|
imm |= ((uint)opCode >> (isThumb ? 21 : 17)) & 0x80;
|
||||||
|
|
||||||
(Immediate, Size) = OpCodeSimdHelper.GetSimdImmediateAndSize(cMode, op, imm);
|
(Immediate, Size) = OpCodeSimdHelper.GetSimdImmediateAndSize(cMode, op, imm);
|
||||||
|
|
||||||
|
@@ -7,10 +7,13 @@
|
|||||||
public int Size { get; }
|
public int Size { get; }
|
||||||
public int Elems { get; }
|
public int Elems { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdImm44(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdImm44(inst, address, opCode, false);
|
||||||
|
public static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdImm44(inst, address, opCode, true);
|
||||||
|
|
||||||
public OpCode32SimdImm44(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32SimdImm44(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
|
IsThumb = isThumb;
|
||||||
|
|
||||||
Size = (opCode >> 8) & 0x3;
|
Size = (opCode >> 8) & 0x3;
|
||||||
|
|
||||||
bool single = Size != 3;
|
bool single = Size != 3;
|
||||||
|
@@ -4,9 +4,10 @@
|
|||||||
{
|
{
|
||||||
public bool U { get; }
|
public bool U { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdLong(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdLong(inst, address, opCode, false);
|
||||||
|
public static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdLong(inst, address, opCode, true);
|
||||||
|
|
||||||
public OpCode32SimdLong(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32SimdLong(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
|
||||||
{
|
{
|
||||||
int imm3h = (opCode >> 19) & 0x7;
|
int imm3h = (opCode >> 19) & 0x7;
|
||||||
|
|
||||||
@@ -18,7 +19,7 @@
|
|||||||
case 4: Size = 2; break;
|
case 4: Size = 2; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
U = ((opCode >> 24) & 0x1) != 0;
|
U = ((opCode >> (isThumb ? 28 : 24)) & 0x1) != 0;
|
||||||
|
|
||||||
RegisterSize = RegisterSize.Simd64;
|
RegisterSize = RegisterSize.Simd64;
|
||||||
|
|
||||||
|
@@ -8,10 +8,13 @@
|
|||||||
public bool Add { get; }
|
public bool Add { get; }
|
||||||
public int Immediate { get; }
|
public int Immediate { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMemImm(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMemImm(inst, address, opCode, false);
|
||||||
|
public static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMemImm(inst, address, opCode, true);
|
||||||
|
|
||||||
public OpCode32SimdMemImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32SimdMemImm(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
|
IsThumb = isThumb;
|
||||||
|
|
||||||
Immediate = opCode & 0xff;
|
Immediate = opCode & 0xff;
|
||||||
|
|
||||||
Rn = (opCode >> 16) & 0xf;
|
Rn = (opCode >> 16) & 0xf;
|
||||||
|
@@ -12,10 +12,13 @@
|
|||||||
public bool DoubleWidth { get; }
|
public bool DoubleWidth { get; }
|
||||||
public bool Add { get; }
|
public bool Add { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMemMult(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMemMult(inst, address, opCode, false);
|
||||||
|
public static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMemMult(inst, address, opCode, true);
|
||||||
|
|
||||||
public OpCode32SimdMemMult(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32SimdMemMult(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
|
IsThumb = isThumb;
|
||||||
|
|
||||||
Rn = (opCode >> 16) & 0xf;
|
Rn = (opCode >> 16) & 0xf;
|
||||||
|
|
||||||
bool isLoad = (opCode & (1 << 20)) != 0;
|
bool isLoad = (opCode & (1 << 20)) != 0;
|
||||||
|
@@ -1,11 +1,10 @@
|
|||||||
using ARMeilleure.State;
|
using ARMeilleure.State;
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace ARMeilleure.Decoders
|
namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCode32SimdMemPair : OpCode32, IOpCode32Simd
|
class OpCode32SimdMemPair : OpCode32, IOpCode32Simd
|
||||||
{
|
{
|
||||||
private static int[] RegsMap =
|
private static int[] _regsMap =
|
||||||
{
|
{
|
||||||
1, 1, 4, 2,
|
1, 1, 4, 2,
|
||||||
1, 1, 3, 1,
|
1, 1, 3, 1,
|
||||||
@@ -24,10 +23,13 @@ namespace ARMeilleure.Decoders
|
|||||||
public int Regs { get; }
|
public int Regs { get; }
|
||||||
public int Increment { get; }
|
public int Increment { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMemPair(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMemPair(inst, address, opCode, false);
|
||||||
|
public static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMemPair(inst, address, opCode, true);
|
||||||
|
|
||||||
public OpCode32SimdMemPair(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32SimdMemPair(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
|
IsThumb = isThumb;
|
||||||
|
|
||||||
Vd = (opCode >> 12) & 0xf;
|
Vd = (opCode >> 12) & 0xf;
|
||||||
Vd |= (opCode >> 18) & 0x10;
|
Vd |= (opCode >> 18) & 0x10;
|
||||||
|
|
||||||
@@ -40,9 +42,9 @@ namespace ARMeilleure.Decoders
|
|||||||
WBack = Rm != RegisterAlias.Aarch32Pc;
|
WBack = Rm != RegisterAlias.Aarch32Pc;
|
||||||
RegisterIndex = Rm != RegisterAlias.Aarch32Pc && Rm != RegisterAlias.Aarch32Sp;
|
RegisterIndex = Rm != RegisterAlias.Aarch32Pc && Rm != RegisterAlias.Aarch32Sp;
|
||||||
|
|
||||||
Regs = RegsMap[(opCode >> 8) & 0xf];
|
Regs = _regsMap[(opCode >> 8) & 0xf];
|
||||||
|
|
||||||
Increment = Math.Min(Regs, ((opCode >> 8) & 0x1) + 1);
|
Increment = ((opCode >> 8) & 0x1) + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -15,10 +15,13 @@ namespace ARMeilleure.Decoders
|
|||||||
public bool Replicate { get; }
|
public bool Replicate { get; }
|
||||||
public int Increment { get; }
|
public int Increment { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMemSingle(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMemSingle(inst, address, opCode, false);
|
||||||
|
public static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMemSingle(inst, address, opCode, true);
|
||||||
|
|
||||||
public OpCode32SimdMemSingle(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32SimdMemSingle(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
|
IsThumb = isThumb;
|
||||||
|
|
||||||
Vd = (opCode >> 12) & 0xf;
|
Vd = (opCode >> 12) & 0xf;
|
||||||
Vd |= (opCode >> 18) & 0x10;
|
Vd |= (opCode >> 18) & 0x10;
|
||||||
|
|
||||||
|
@@ -11,10 +11,13 @@
|
|||||||
public int Opc1 { get; }
|
public int Opc1 { get; }
|
||||||
public int Opc2 { get; }
|
public int Opc2 { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMovGp(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMovGp(inst, address, opCode, false);
|
||||||
|
public static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMovGp(inst, address, opCode, true);
|
||||||
|
|
||||||
public OpCode32SimdMovGp(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32SimdMovGp(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
|
IsThumb = isThumb;
|
||||||
|
|
||||||
// Which one is used is instruction dependant.
|
// Which one is used is instruction dependant.
|
||||||
Op = (opCode >> 20) & 0x1;
|
Op = (opCode >> 20) & 0x1;
|
||||||
|
|
||||||
|
@@ -9,10 +9,13 @@
|
|||||||
public int Rt2 { get; }
|
public int Rt2 { get; }
|
||||||
public int Op { get; }
|
public int Op { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMovGpDouble(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMovGpDouble(inst, address, opCode, false);
|
||||||
|
public static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMovGpDouble(inst, address, opCode, true);
|
||||||
|
|
||||||
public OpCode32SimdMovGpDouble(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32SimdMovGpDouble(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
|
IsThumb = isThumb;
|
||||||
|
|
||||||
// Which one is used is instruction dependant.
|
// Which one is used is instruction dependant.
|
||||||
Op = (opCode >> 20) & 0x1;
|
Op = (opCode >> 20) & 0x1;
|
||||||
|
|
||||||
|
@@ -11,10 +11,13 @@
|
|||||||
|
|
||||||
public int Index { get; }
|
public int Index { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMovGpElem(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMovGpElem(inst, address, opCode, false);
|
||||||
|
public static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMovGpElem(inst, address, opCode, true);
|
||||||
|
|
||||||
public OpCode32SimdMovGpElem(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32SimdMovGpElem(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
|
IsThumb = isThumb;
|
||||||
|
|
||||||
Op = (opCode >> 20) & 0x1;
|
Op = (opCode >> 20) & 0x1;
|
||||||
U = ((opCode >> 23) & 1) != 0;
|
U = ((opCode >> 23) & 1) != 0;
|
||||||
|
|
||||||
|
@@ -2,9 +2,10 @@ namespace ARMeilleure.Decoders
|
|||||||
{
|
{
|
||||||
class OpCode32SimdMovn : OpCode32Simd
|
class OpCode32SimdMovn : OpCode32Simd
|
||||||
{
|
{
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMovn(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMovn(inst, address, opCode, false);
|
||||||
|
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMovn(inst, address, opCode, true);
|
||||||
|
|
||||||
public OpCode32SimdMovn(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32SimdMovn(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
|
||||||
{
|
{
|
||||||
Size = (opCode >> 18) & 0x3;
|
Size = (opCode >> 18) & 0x3;
|
||||||
}
|
}
|
||||||
|
@@ -8,9 +8,10 @@
|
|||||||
public int In => GetQuadwordSubindex(Vn) << (3 - Size);
|
public int In => GetQuadwordSubindex(Vn) << (3 - Size);
|
||||||
public int Fn => GetQuadwordSubindex(Vn) << (1 - (Size & 1));
|
public int Fn => GetQuadwordSubindex(Vn) << (1 - (Size & 1));
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdReg(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdReg(inst, address, opCode, false);
|
||||||
|
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdReg(inst, address, opCode, true);
|
||||||
|
|
||||||
public OpCode32SimdReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32SimdReg(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
|
||||||
{
|
{
|
||||||
Vn = ((opCode >> 3) & 0x10) | ((opCode >> 16) & 0xf);
|
Vn = ((opCode >> 3) & 0x10) | ((opCode >> 16) & 0xf);
|
||||||
|
|
||||||
|
@@ -2,11 +2,12 @@
|
|||||||
{
|
{
|
||||||
class OpCode32SimdRegElem : OpCode32SimdReg
|
class OpCode32SimdRegElem : OpCode32SimdReg
|
||||||
{
|
{
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdRegElem(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdRegElem(inst, address, opCode, false);
|
||||||
|
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdRegElem(inst, address, opCode, true);
|
||||||
|
|
||||||
public OpCode32SimdRegElem(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32SimdRegElem(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
|
||||||
{
|
{
|
||||||
Q = ((opCode >> 24) & 0x1) != 0;
|
Q = ((opCode >> (isThumb ? 28 : 24)) & 0x1) != 0;
|
||||||
F = ((opCode >> 8) & 0x1) != 0;
|
F = ((opCode >> 8) & 0x1) != 0;
|
||||||
Size = (opCode >> 20) & 0x3;
|
Size = (opCode >> 20) & 0x3;
|
||||||
|
|
||||||
|
@@ -2,9 +2,10 @@
|
|||||||
{
|
{
|
||||||
class OpCode32SimdRegElemLong : OpCode32SimdRegElem
|
class OpCode32SimdRegElemLong : OpCode32SimdRegElem
|
||||||
{
|
{
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdRegElemLong(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdRegElemLong(inst, address, opCode, false);
|
||||||
|
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdRegElemLong(inst, address, opCode, true);
|
||||||
|
|
||||||
public OpCode32SimdRegElemLong(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32SimdRegElemLong(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
|
||||||
{
|
{
|
||||||
Q = false;
|
Q = false;
|
||||||
F = false;
|
F = false;
|
||||||
|
@@ -4,9 +4,10 @@
|
|||||||
{
|
{
|
||||||
public bool Polynomial { get; }
|
public bool Polynomial { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdRegLong(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdRegLong(inst, address, opCode, false);
|
||||||
|
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdRegLong(inst, address, opCode, true);
|
||||||
|
|
||||||
public OpCode32SimdRegLong(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32SimdRegLong(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
|
||||||
{
|
{
|
||||||
Q = false;
|
Q = false;
|
||||||
RegisterSize = RegisterSize.Simd64;
|
RegisterSize = RegisterSize.Simd64;
|
||||||
|
@@ -4,9 +4,10 @@
|
|||||||
{
|
{
|
||||||
public int Vn { get; }
|
public int Vn { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdRegS(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdRegS(inst, address, opCode, false);
|
||||||
|
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdRegS(inst, address, opCode, true);
|
||||||
|
|
||||||
public OpCode32SimdRegS(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32SimdRegS(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
|
||||||
{
|
{
|
||||||
bool single = Size != 3;
|
bool single = Size != 3;
|
||||||
if (single)
|
if (single)
|
||||||
|
@@ -2,9 +2,10 @@
|
|||||||
{
|
{
|
||||||
class OpCode32SimdRegWide : OpCode32SimdReg
|
class OpCode32SimdRegWide : OpCode32SimdReg
|
||||||
{
|
{
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdRegWide(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdRegWide(inst, address, opCode, false);
|
||||||
|
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdRegWide(inst, address, opCode, true);
|
||||||
|
|
||||||
public OpCode32SimdRegWide(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32SimdRegWide(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
|
||||||
{
|
{
|
||||||
Q = false;
|
Q = false;
|
||||||
RegisterSize = RegisterSize.Simd64;
|
RegisterSize = RegisterSize.Simd64;
|
||||||
|
@@ -2,9 +2,10 @@
|
|||||||
{
|
{
|
||||||
class OpCode32SimdRev : OpCode32SimdCmpZ
|
class OpCode32SimdRev : OpCode32SimdCmpZ
|
||||||
{
|
{
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdRev(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdRev(inst, address, opCode, false);
|
||||||
|
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdRev(inst, address, opCode, true);
|
||||||
|
|
||||||
public OpCode32SimdRev(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32SimdRev(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
|
||||||
{
|
{
|
||||||
if (Opc + Size >= 3)
|
if (Opc + Size >= 3)
|
||||||
{
|
{
|
||||||
|
@@ -8,10 +8,13 @@
|
|||||||
public int Opc2 { get; } // opc2 or RM (opc2<1:0>) [Vcvt, Vrint].
|
public int Opc2 { get; } // opc2 or RM (opc2<1:0>) [Vcvt, Vrint].
|
||||||
public int Size { get; protected set; }
|
public int Size { get; protected set; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdS(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdS(inst, address, opCode, false);
|
||||||
|
public static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdS(inst, address, opCode, true);
|
||||||
|
|
||||||
public OpCode32SimdS(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32SimdS(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
|
IsThumb = isThumb;
|
||||||
|
|
||||||
Opc = (opCode >> 15) & 0x3;
|
Opc = (opCode >> 15) & 0x3;
|
||||||
Opc2 = (opCode >> 16) & 0x7;
|
Opc2 = (opCode >> 16) & 0x7;
|
||||||
|
|
||||||
|
@@ -4,9 +4,10 @@
|
|||||||
{
|
{
|
||||||
public OpCode32SimdSelMode Cc { get; }
|
public OpCode32SimdSelMode Cc { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdSel(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdSel(inst, address, opCode, false);
|
||||||
|
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdSel(inst, address, opCode, true);
|
||||||
|
|
||||||
public OpCode32SimdSel(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32SimdSel(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
|
||||||
{
|
{
|
||||||
Cc = (OpCode32SimdSelMode)((opCode >> 20) & 3);
|
Cc = (OpCode32SimdSelMode)((opCode >> 20) & 3);
|
||||||
}
|
}
|
||||||
|
@@ -4,9 +4,10 @@
|
|||||||
{
|
{
|
||||||
public int Shift { get; }
|
public int Shift { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdShImm(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdShImm(inst, address, opCode, false);
|
||||||
|
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdShImm(inst, address, opCode, true);
|
||||||
|
|
||||||
public OpCode32SimdShImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32SimdShImm(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
|
||||||
{
|
{
|
||||||
int imm6 = (opCode >> 16) & 0x3f;
|
int imm6 = (opCode >> 16) & 0x3f;
|
||||||
int limm6 = ((opCode >> 1) & 0x40) | imm6;
|
int limm6 = ((opCode >> 1) & 0x40) | imm6;
|
||||||
|
@@ -4,9 +4,10 @@
|
|||||||
{
|
{
|
||||||
public int Shift { get; }
|
public int Shift { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdShImmLong(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdShImmLong(inst, address, opCode, false);
|
||||||
|
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdShImmLong(inst, address, opCode, true);
|
||||||
|
|
||||||
public OpCode32SimdShImmLong(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32SimdShImmLong(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
|
||||||
{
|
{
|
||||||
Q = false;
|
Q = false;
|
||||||
RegisterSize = RegisterSize.Simd64;
|
RegisterSize = RegisterSize.Simd64;
|
||||||
|
@@ -2,8 +2,9 @@
|
|||||||
{
|
{
|
||||||
class OpCode32SimdShImmNarrow : OpCode32SimdShImm
|
class OpCode32SimdShImmNarrow : OpCode32SimdShImm
|
||||||
{
|
{
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdShImmNarrow(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdShImmNarrow(inst, address, opCode, false);
|
||||||
|
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdShImmNarrow(inst, address, opCode, true);
|
||||||
|
|
||||||
public OpCode32SimdShImmNarrow(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) { }
|
public OpCode32SimdShImmNarrow(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb) { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,10 +5,13 @@
|
|||||||
public int Rt { get; }
|
public int Rt { get; }
|
||||||
public int Sreg { get; }
|
public int Sreg { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdSpecial(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdSpecial(inst, address, opCode, false);
|
||||||
|
public static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdSpecial(inst, address, opCode, true);
|
||||||
|
|
||||||
public OpCode32SimdSpecial(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32SimdSpecial(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
|
IsThumb = isThumb;
|
||||||
|
|
||||||
Rt = (opCode >> 12) & 0xf;
|
Rt = (opCode >> 12) & 0xf;
|
||||||
Sreg = (opCode >> 16) & 0xf;
|
Sreg = (opCode >> 16) & 0xf;
|
||||||
}
|
}
|
||||||
|
@@ -2,9 +2,10 @@
|
|||||||
{
|
{
|
||||||
class OpCode32SimdSqrte : OpCode32Simd
|
class OpCode32SimdSqrte : OpCode32Simd
|
||||||
{
|
{
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdSqrte(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdSqrte(inst, address, opCode, false);
|
||||||
|
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdSqrte(inst, address, opCode, true);
|
||||||
|
|
||||||
public OpCode32SimdSqrte(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32SimdSqrte(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
|
||||||
{
|
{
|
||||||
Size = (opCode >> 18) & 0x1;
|
Size = (opCode >> 18) & 0x1;
|
||||||
F = ((opCode >> 8) & 0x1) != 0;
|
F = ((opCode >> 8) & 0x1) != 0;
|
||||||
|
@@ -4,9 +4,10 @@
|
|||||||
{
|
{
|
||||||
public int Length { get; }
|
public int Length { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdTbl(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdTbl(inst, address, opCode, false);
|
||||||
|
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdTbl(inst, address, opCode, true);
|
||||||
|
|
||||||
public OpCode32SimdTbl(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32SimdTbl(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
|
||||||
{
|
{
|
||||||
Length = (opCode >> 8) & 3;
|
Length = (opCode >> 8) & 3;
|
||||||
Size = 0;
|
Size = 0;
|
||||||
|
@@ -8,6 +8,7 @@ namespace ARMeilleure.Decoders
|
|||||||
{
|
{
|
||||||
Cond = Condition.Al;
|
Cond = Condition.Al;
|
||||||
|
|
||||||
|
IsThumb = true;
|
||||||
OpCodeSizeInBytes = 2;
|
OpCodeSizeInBytes = 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
{
|
{
|
||||||
Cond = Condition.Al;
|
Cond = Condition.Al;
|
||||||
|
|
||||||
|
IsThumb = true;
|
||||||
OpCodeSizeInBytes = 4;
|
OpCodeSizeInBytes = 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
22
ARMeilleure/Decoders/OpCodeT32AluBf.cs
Normal file
22
ARMeilleure/Decoders/OpCodeT32AluBf.cs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT32AluBf : OpCodeT32, IOpCode32AluBf
|
||||||
|
{
|
||||||
|
public int Rd { get; }
|
||||||
|
public int Rn { get; }
|
||||||
|
|
||||||
|
public int Msb { get; }
|
||||||
|
public int Lsb { get; }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32AluBf(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT32AluBf(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rd = (opCode >> 8) & 0xf;
|
||||||
|
Rn = (opCode >> 16) & 0xf;
|
||||||
|
|
||||||
|
Msb = (opCode >> 0) & 0x1f;
|
||||||
|
Lsb = ((opCode >> 6) & 0x3) | ((opCode >> 10) & 0x1c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
ARMeilleure/Decoders/OpCodeT32AluMla.cs
Normal file
29
ARMeilleure/Decoders/OpCodeT32AluMla.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT32AluMla : OpCodeT32, IOpCode32AluMla
|
||||||
|
{
|
||||||
|
public int Rn { get; }
|
||||||
|
public int Rm { get; }
|
||||||
|
public int Ra { get; }
|
||||||
|
public int Rd { get; }
|
||||||
|
|
||||||
|
public bool NHigh { get; }
|
||||||
|
public bool MHigh { get; }
|
||||||
|
public bool R { get; }
|
||||||
|
public bool? SetFlags => false;
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32AluMla(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT32AluMla(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rm = (opCode >> 0) & 0xf;
|
||||||
|
Rd = (opCode >> 8) & 0xf;
|
||||||
|
Ra = (opCode >> 12) & 0xf;
|
||||||
|
Rn = (opCode >> 16) & 0xf;
|
||||||
|
R = (opCode & (1 << 4)) != 0;
|
||||||
|
|
||||||
|
MHigh = ((opCode >> 4) & 0x1) == 1;
|
||||||
|
NHigh = ((opCode >> 5) & 0x1) == 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
28
ARMeilleure/Decoders/OpCodeT32AluUmull.cs
Normal file
28
ARMeilleure/Decoders/OpCodeT32AluUmull.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT32AluUmull : OpCodeT32, IOpCode32AluUmull
|
||||||
|
{
|
||||||
|
public int RdLo { get; }
|
||||||
|
public int RdHi { get; }
|
||||||
|
public int Rn { get; }
|
||||||
|
public int Rm { get; }
|
||||||
|
|
||||||
|
public bool NHigh { get; }
|
||||||
|
public bool MHigh { get; }
|
||||||
|
|
||||||
|
public bool? SetFlags => false;
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32AluUmull(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT32AluUmull(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rm = (opCode >> 0) & 0xf;
|
||||||
|
RdHi = (opCode >> 8) & 0xf;
|
||||||
|
RdLo = (opCode >> 12) & 0xf;
|
||||||
|
Rn = (opCode >> 16) & 0xf;
|
||||||
|
|
||||||
|
MHigh = ((opCode >> 4) & 0x1) == 1;
|
||||||
|
NHigh = ((opCode >> 5) & 0x1) == 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
18
ARMeilleure/Decoders/OpCodeT32AluUx.cs
Normal file
18
ARMeilleure/Decoders/OpCodeT32AluUx.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using ARMeilleure.State;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT32AluUx : OpCodeT32AluReg, IOpCode32AluUx
|
||||||
|
{
|
||||||
|
public int Rotate { get; }
|
||||||
|
public int RotateBits => Rotate * 8;
|
||||||
|
public bool Add => Rn != RegisterAlias.Aarch32Pc;
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32AluUx(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT32AluUx(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rotate = (opCode >> 4) & 0x3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -27,7 +27,7 @@ namespace ARMeilleure.Decoders
|
|||||||
int i2 = j2 ^ s ^ 1;
|
int i2 = j2 ^ s ^ 1;
|
||||||
|
|
||||||
int imm32 = imm11 | (imm10 << 11) | (i2 << 21) | (i1 << 22) | (s << 23);
|
int imm32 = imm11 | (imm10 << 11) | (i2 << 21) | (i1 << 22) | (s << 23);
|
||||||
imm32 = (imm32 << 9) >> 8;
|
imm32 = (imm32 << 8) >> 7;
|
||||||
|
|
||||||
Immediate = pc + imm32;
|
Immediate = pc + imm32;
|
||||||
}
|
}
|
||||||
|
@@ -4,6 +4,7 @@ namespace ARMeilleure.Decoders
|
|||||||
{
|
{
|
||||||
public int Rd => 0;
|
public int Rd => 0;
|
||||||
public int Rt { get; }
|
public int Rt { get; }
|
||||||
|
public int Rt2 { get; }
|
||||||
public int Rn { get; }
|
public int Rn { get; }
|
||||||
|
|
||||||
public bool WBack => false;
|
public bool WBack => false;
|
||||||
@@ -17,6 +18,7 @@ namespace ARMeilleure.Decoders
|
|||||||
|
|
||||||
public OpCodeT32MemLdEx(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCodeT32MemLdEx(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
|
Rt2 = (opCode >> 8) & 0xf;
|
||||||
Rt = (opCode >> 12) & 0xf;
|
Rt = (opCode >> 12) & 0xf;
|
||||||
Rn = (opCode >> 16) & 0xf;
|
Rn = (opCode >> 16) & 0xf;
|
||||||
}
|
}
|
||||||
|
@@ -4,6 +4,7 @@ namespace ARMeilleure.Decoders
|
|||||||
{
|
{
|
||||||
public int Rd { get; }
|
public int Rd { get; }
|
||||||
public int Rt { get; }
|
public int Rt { get; }
|
||||||
|
public int Rt2 { get; }
|
||||||
public int Rn { get; }
|
public int Rn { get; }
|
||||||
|
|
||||||
public bool WBack => false;
|
public bool WBack => false;
|
||||||
@@ -18,6 +19,7 @@ namespace ARMeilleure.Decoders
|
|||||||
public OpCodeT32MemStEx(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCodeT32MemStEx(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
Rd = (opCode >> 0) & 0xf;
|
Rd = (opCode >> 0) & 0xf;
|
||||||
|
Rt2 = (opCode >> 8) & 0xf;
|
||||||
Rt = (opCode >> 12) & 0xf;
|
Rt = (opCode >> 12) & 0xf;
|
||||||
Rn = (opCode >> 16) & 0xf;
|
Rn = (opCode >> 16) & 0xf;
|
||||||
}
|
}
|
||||||
|
@@ -1,9 +1,6 @@
|
|||||||
using ARMeilleure.Common;
|
|
||||||
using System.Runtime.Intrinsics;
|
|
||||||
|
|
||||||
namespace ARMeilleure.Decoders
|
namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCodeT32MovImm16 : OpCodeT32Alu, IOpCode32AluImm
|
class OpCodeT32MovImm16 : OpCodeT32Alu, IOpCode32AluImm16
|
||||||
{
|
{
|
||||||
public int Immediate { get; }
|
public int Immediate { get; }
|
||||||
|
|
||||||
|
@@ -93,6 +93,7 @@ namespace ARMeilleure.Decoders
|
|||||||
SetA64("00011010110xxxxx010101xxxxxxxxxx", InstName.Crc32ch, InstEmit.Crc32ch, OpCodeAluBinary.Create);
|
SetA64("00011010110xxxxx010101xxxxxxxxxx", InstName.Crc32ch, InstEmit.Crc32ch, OpCodeAluBinary.Create);
|
||||||
SetA64("00011010110xxxxx010110xxxxxxxxxx", InstName.Crc32cw, InstEmit.Crc32cw, OpCodeAluBinary.Create);
|
SetA64("00011010110xxxxx010110xxxxxxxxxx", InstName.Crc32cw, InstEmit.Crc32cw, OpCodeAluBinary.Create);
|
||||||
SetA64("10011010110xxxxx010111xxxxxxxxxx", InstName.Crc32cx, InstEmit.Crc32cx, OpCodeAluBinary.Create);
|
SetA64("10011010110xxxxx010111xxxxxxxxxx", InstName.Crc32cx, InstEmit.Crc32cx, OpCodeAluBinary.Create);
|
||||||
|
SetA64("11010101000000110010001010011111", InstName.Csdb, InstEmit.Csdb, OpCodeSystem.Create);
|
||||||
SetA64("x0011010100xxxxxxxxx00xxxxxxxxxx", InstName.Csel, InstEmit.Csel, OpCodeCsel.Create);
|
SetA64("x0011010100xxxxxxxxx00xxxxxxxxxx", InstName.Csel, InstEmit.Csel, OpCodeCsel.Create);
|
||||||
SetA64("x0011010100xxxxxxxxx01xxxxxxxxxx", InstName.Csinc, InstEmit.Csinc, OpCodeCsel.Create);
|
SetA64("x0011010100xxxxxxxxx01xxxxxxxxxx", InstName.Csinc, InstEmit.Csinc, OpCodeCsel.Create);
|
||||||
SetA64("x1011010100xxxxxxxxx00xxxxxxxxxx", InstName.Csinv, InstEmit.Csinv, OpCodeCsel.Create);
|
SetA64("x1011010100xxxxxxxxx00xxxxxxxxxx", InstName.Csinv, InstEmit.Csinv, OpCodeCsel.Create);
|
||||||
@@ -107,7 +108,6 @@ namespace ARMeilleure.Decoders
|
|||||||
SetA64("11001010xx0xxxxxxxxxxxxxxxxxxxxx", InstName.Eor, InstEmit.Eor, OpCodeAluRs.Create);
|
SetA64("11001010xx0xxxxxxxxxxxxxxxxxxxxx", InstName.Eor, InstEmit.Eor, OpCodeAluRs.Create);
|
||||||
SetA64("00010011100xxxxx0xxxxxxxxxxxxxxx", InstName.Extr, InstEmit.Extr, OpCodeAluRs.Create);
|
SetA64("00010011100xxxxx0xxxxxxxxxxxxxxx", InstName.Extr, InstEmit.Extr, OpCodeAluRs.Create);
|
||||||
SetA64("10010011110xxxxxxxxxxxxxxxxxxxxx", InstName.Extr, InstEmit.Extr, OpCodeAluRs.Create);
|
SetA64("10010011110xxxxxxxxxxxxxxxxxxxxx", InstName.Extr, InstEmit.Extr, OpCodeAluRs.Create);
|
||||||
SetA64("11010101000000110010xxxxxxx11111", InstName.Hint, InstEmit.Hint, OpCodeSystem.Create);
|
|
||||||
SetA64("11010101000000110011xxxx11011111", InstName.Isb, InstEmit.Isb, OpCodeSystem.Create);
|
SetA64("11010101000000110011xxxx11011111", InstName.Isb, InstEmit.Isb, OpCodeSystem.Create);
|
||||||
SetA64("xx001000110xxxxx1xxxxxxxxxxxxxxx", InstName.Ldar, InstEmit.Ldar, OpCodeMemEx.Create);
|
SetA64("xx001000110xxxxx1xxxxxxxxxxxxxxx", InstName.Ldar, InstEmit.Ldar, OpCodeMemEx.Create);
|
||||||
SetA64("1x001000011xxxxx1xxxxxxxxxxxxxxx", InstName.Ldaxp, InstEmit.Ldaxp, OpCodeMemEx.Create);
|
SetA64("1x001000011xxxxx1xxxxxxxxxxxxxxx", InstName.Ldaxp, InstEmit.Ldaxp, OpCodeMemEx.Create);
|
||||||
@@ -159,6 +159,8 @@ namespace ARMeilleure.Decoders
|
|||||||
SetA64("00010011000xxxxx0xxxxxxxxxxxxxxx", InstName.Sbfm, InstEmit.Sbfm, OpCodeBfm.Create);
|
SetA64("00010011000xxxxx0xxxxxxxxxxxxxxx", InstName.Sbfm, InstEmit.Sbfm, OpCodeBfm.Create);
|
||||||
SetA64("1001001101xxxxxxxxxxxxxxxxxxxxxx", InstName.Sbfm, InstEmit.Sbfm, OpCodeBfm.Create);
|
SetA64("1001001101xxxxxxxxxxxxxxxxxxxxxx", InstName.Sbfm, InstEmit.Sbfm, OpCodeBfm.Create);
|
||||||
SetA64("x0011010110xxxxx000011xxxxxxxxxx", InstName.Sdiv, InstEmit.Sdiv, OpCodeAluBinary.Create);
|
SetA64("x0011010110xxxxx000011xxxxxxxxxx", InstName.Sdiv, InstEmit.Sdiv, OpCodeAluBinary.Create);
|
||||||
|
SetA64("11010101000000110010000010011111", InstName.Sev, InstEmit.Nop, OpCodeSystem.Create);
|
||||||
|
SetA64("11010101000000110010000010111111", InstName.Sevl, InstEmit.Nop, OpCodeSystem.Create);
|
||||||
SetA64("10011011001xxxxx0xxxxxxxxxxxxxxx", InstName.Smaddl, InstEmit.Smaddl, OpCodeMul.Create);
|
SetA64("10011011001xxxxx0xxxxxxxxxxxxxxx", InstName.Smaddl, InstEmit.Smaddl, OpCodeMul.Create);
|
||||||
SetA64("10011011001xxxxx1xxxxxxxxxxxxxxx", InstName.Smsubl, InstEmit.Smsubl, OpCodeMul.Create);
|
SetA64("10011011001xxxxx1xxxxxxxxxxxxxxx", InstName.Smsubl, InstEmit.Smsubl, OpCodeMul.Create);
|
||||||
SetA64("10011011010xxxxx0xxxxxxxxxxxxxxx", InstName.Smulh, InstEmit.Smulh, OpCodeMul.Create);
|
SetA64("10011011010xxxxx0xxxxxxxxxxxxxxx", InstName.Smulh, InstEmit.Smulh, OpCodeMul.Create);
|
||||||
@@ -191,6 +193,9 @@ namespace ARMeilleure.Decoders
|
|||||||
SetA64("10011011101xxxxx0xxxxxxxxxxxxxxx", InstName.Umaddl, InstEmit.Umaddl, OpCodeMul.Create);
|
SetA64("10011011101xxxxx0xxxxxxxxxxxxxxx", InstName.Umaddl, InstEmit.Umaddl, OpCodeMul.Create);
|
||||||
SetA64("10011011101xxxxx1xxxxxxxxxxxxxxx", InstName.Umsubl, InstEmit.Umsubl, OpCodeMul.Create);
|
SetA64("10011011101xxxxx1xxxxxxxxxxxxxxx", InstName.Umsubl, InstEmit.Umsubl, OpCodeMul.Create);
|
||||||
SetA64("10011011110xxxxx0xxxxxxxxxxxxxxx", InstName.Umulh, InstEmit.Umulh, OpCodeMul.Create);
|
SetA64("10011011110xxxxx0xxxxxxxxxxxxxxx", InstName.Umulh, InstEmit.Umulh, OpCodeMul.Create);
|
||||||
|
SetA64("11010101000000110010000001011111", InstName.Wfe, InstEmit.Nop, OpCodeSystem.Create);
|
||||||
|
SetA64("11010101000000110010000001111111", InstName.Wfi, InstEmit.Nop, OpCodeSystem.Create);
|
||||||
|
SetA64("11010101000000110010000000111111", InstName.Yield, InstEmit.Nop, OpCodeSystem.Create);
|
||||||
|
|
||||||
// FP & SIMD
|
// FP & SIMD
|
||||||
SetA64("0101111011100000101110xxxxxxxxxx", InstName.Abs_S, InstEmit.Abs_S, OpCodeSimd.Create);
|
SetA64("0101111011100000101110xxxxxxxxxx", InstName.Abs_S, InstEmit.Abs_S, OpCodeSimd.Create);
|
||||||
@@ -669,6 +674,17 @@ namespace ARMeilleure.Decoders
|
|||||||
SetA32("<<<<0010001xxxxxxxxxxxxxxxxxxxxx", InstName.Eor, InstEmit32.Eor, OpCode32AluImm.Create);
|
SetA32("<<<<0010001xxxxxxxxxxxxxxxxxxxxx", InstName.Eor, InstEmit32.Eor, OpCode32AluImm.Create);
|
||||||
SetA32("<<<<0000001xxxxxxxxxxxxxxxx0xxxx", InstName.Eor, InstEmit32.Eor, OpCode32AluRsImm.Create);
|
SetA32("<<<<0000001xxxxxxxxxxxxxxxx0xxxx", InstName.Eor, InstEmit32.Eor, OpCode32AluRsImm.Create);
|
||||||
SetA32("<<<<0000001xxxxxxxxxxxxx0xx1xxxx", InstName.Eor, InstEmit32.Eor, OpCode32AluRsReg.Create);
|
SetA32("<<<<0000001xxxxxxxxxxxxx0xx1xxxx", InstName.Eor, InstEmit32.Eor, OpCode32AluRsReg.Create);
|
||||||
|
SetA32("<<<<0011001000001111000000010000", InstName.Esb, InstEmit32.Nop, OpCode32.Create); // Error Synchronization Barrier (FEAT_RAS)
|
||||||
|
SetA32("<<<<001100100000111100000000011x", InstName.Hint, InstEmit32.Nop, OpCode32.Create); // Reserved Hint
|
||||||
|
SetA32("<<<<0011001000001111000000001xxx", InstName.Hint, InstEmit32.Nop, OpCode32.Create); // Reserved Hint
|
||||||
|
SetA32("<<<<0011001000001111000000010001", InstName.Hint, InstEmit32.Nop, OpCode32.Create); // Reserved Hint
|
||||||
|
SetA32("<<<<0011001000001111000000010011", InstName.Hint, InstEmit32.Nop, OpCode32.Create); // Reserved Hint
|
||||||
|
SetA32("<<<<0011001000001111000000010101", InstName.Hint, InstEmit32.Nop, OpCode32.Create); // Reserved Hint
|
||||||
|
SetA32("<<<<001100100000111100000001011x", InstName.Hint, InstEmit32.Nop, OpCode32.Create); // Reserved Hint
|
||||||
|
SetA32("<<<<0011001000001111000000011xxx", InstName.Hint, InstEmit32.Nop, OpCode32.Create); // Reserved Hint
|
||||||
|
SetA32("<<<<00110010000011110000001xxxxx", InstName.Hint, InstEmit32.Nop, OpCode32.Create); // Reserved Hint
|
||||||
|
SetA32("<<<<0011001000001111000001xxxxxx", InstName.Hint, InstEmit32.Nop, OpCode32.Create); // Reserved Hint
|
||||||
|
SetA32("<<<<001100100000111100001xxxxxxx", InstName.Hint, InstEmit32.Nop, OpCode32.Create); // Reserved Hint
|
||||||
SetA32("1111010101111111111100000110xxxx", InstName.Isb, InstEmit32.Nop, OpCode32.Create);
|
SetA32("1111010101111111111100000110xxxx", InstName.Isb, InstEmit32.Nop, OpCode32.Create);
|
||||||
SetA32("<<<<00011001xxxxxxxx110010011111", InstName.Lda, InstEmit32.Lda, OpCode32MemLdEx.Create);
|
SetA32("<<<<00011001xxxxxxxx110010011111", InstName.Lda, InstEmit32.Lda, OpCode32MemLdEx.Create);
|
||||||
SetA32("<<<<00011101xxxxxxxx110010011111", InstName.Ldab, InstEmit32.Ldab, OpCode32MemLdEx.Create);
|
SetA32("<<<<00011101xxxxxxxx110010011111", InstName.Ldab, InstEmit32.Ldab, OpCode32MemLdEx.Create);
|
||||||
@@ -727,11 +743,15 @@ namespace ARMeilleure.Decoders
|
|||||||
SetA32("<<<<0010111xxxxxxxxxxxxxxxxxxxxx", InstName.Rsc, InstEmit32.Rsc, OpCode32AluImm.Create);
|
SetA32("<<<<0010111xxxxxxxxxxxxxxxxxxxxx", InstName.Rsc, InstEmit32.Rsc, OpCode32AluImm.Create);
|
||||||
SetA32("<<<<0000111xxxxxxxxxxxxxxxx0xxxx", InstName.Rsc, InstEmit32.Rsc, OpCode32AluRsImm.Create);
|
SetA32("<<<<0000111xxxxxxxxxxxxxxxx0xxxx", InstName.Rsc, InstEmit32.Rsc, OpCode32AluRsImm.Create);
|
||||||
SetA32("<<<<0000111xxxxxxxxxxxxx0xx1xxxx", InstName.Rsc, InstEmit32.Rsc, OpCode32AluRsReg.Create);
|
SetA32("<<<<0000111xxxxxxxxxxxxx0xx1xxxx", InstName.Rsc, InstEmit32.Rsc, OpCode32AluRsReg.Create);
|
||||||
|
SetA32("<<<<01100001xxxxxxxx11111001xxxx", InstName.Sadd8, InstEmit32.Sadd8, OpCode32AluReg.Create);
|
||||||
SetA32("<<<<0010110xxxxxxxxxxxxxxxxxxxxx", InstName.Sbc, InstEmit32.Sbc, OpCode32AluImm.Create);
|
SetA32("<<<<0010110xxxxxxxxxxxxxxxxxxxxx", InstName.Sbc, InstEmit32.Sbc, OpCode32AluImm.Create);
|
||||||
SetA32("<<<<0000110xxxxxxxxxxxxxxxx0xxxx", InstName.Sbc, InstEmit32.Sbc, OpCode32AluRsImm.Create);
|
SetA32("<<<<0000110xxxxxxxxxxxxxxxx0xxxx", InstName.Sbc, InstEmit32.Sbc, OpCode32AluRsImm.Create);
|
||||||
SetA32("<<<<0000110xxxxxxxxxxxxx0xx1xxxx", InstName.Sbc, InstEmit32.Sbc, OpCode32AluRsReg.Create);
|
SetA32("<<<<0000110xxxxxxxxxxxxx0xx1xxxx", InstName.Sbc, InstEmit32.Sbc, OpCode32AluRsReg.Create);
|
||||||
SetA32("<<<<0111101xxxxxxxxxxxxxx101xxxx", InstName.Sbfx, InstEmit32.Sbfx, OpCode32AluBf.Create);
|
SetA32("<<<<0111101xxxxxxxxxxxxxx101xxxx", InstName.Sbfx, InstEmit32.Sbfx, OpCode32AluBf.Create);
|
||||||
SetA32("<<<<01110001xxxx1111xxxx0001xxxx", InstName.Sdiv, InstEmit32.Sdiv, OpCode32AluMla.Create);
|
SetA32("<<<<01110001xxxx1111xxxx0001xxxx", InstName.Sdiv, InstEmit32.Sdiv, OpCode32AluMla.Create);
|
||||||
|
SetA32("<<<<01101000xxxxxxxx11111011xxxx", InstName.Sel, InstEmit32.Sel, OpCode32AluReg.Create);
|
||||||
|
SetA32("<<<<0011001000001111000000000100", InstName.Sev, InstEmit32.Nop, OpCode32.Create);
|
||||||
|
SetA32("<<<<0011001000001111000000000101", InstName.Sevl, InstEmit32.Nop, OpCode32.Create);
|
||||||
SetA32("<<<<01100011xxxxxxxx11111001xxxx", InstName.Shadd8, InstEmit32.Shadd8, OpCode32AluReg.Create);
|
SetA32("<<<<01100011xxxxxxxx11111001xxxx", InstName.Shadd8, InstEmit32.Shadd8, OpCode32AluReg.Create);
|
||||||
SetA32("<<<<01100011xxxxxxxx11111111xxxx", InstName.Shsub8, InstEmit32.Shsub8, OpCode32AluReg.Create);
|
SetA32("<<<<01100011xxxxxxxx11111111xxxx", InstName.Shsub8, InstEmit32.Shsub8, OpCode32AluReg.Create);
|
||||||
SetA32("<<<<00010000xxxxxxxxxxxx1xx0xxxx", InstName.Smla__, InstEmit32.Smla__, OpCode32AluMla.Create);
|
SetA32("<<<<00010000xxxxxxxxxxxx1xx0xxxx", InstName.Smla__, InstEmit32.Smla__, OpCode32AluMla.Create);
|
||||||
@@ -745,6 +765,7 @@ namespace ARMeilleure.Decoders
|
|||||||
SetA32("<<<<00010010xxxx0000xxxx1x10xxxx", InstName.Smulw_, InstEmit32.Smulw_, OpCode32AluMla.Create);
|
SetA32("<<<<00010010xxxx0000xxxx1x10xxxx", InstName.Smulw_, InstEmit32.Smulw_, OpCode32AluMla.Create);
|
||||||
SetA32("<<<<0110101xxxxxxxxxxxxxxx01xxxx", InstName.Ssat, InstEmit32.Ssat, OpCode32Sat.Create);
|
SetA32("<<<<0110101xxxxxxxxxxxxxxx01xxxx", InstName.Ssat, InstEmit32.Ssat, OpCode32Sat.Create);
|
||||||
SetA32("<<<<01101010xxxxxxxx11110011xxxx", InstName.Ssat16, InstEmit32.Ssat16, OpCode32Sat16.Create);
|
SetA32("<<<<01101010xxxxxxxx11110011xxxx", InstName.Ssat16, InstEmit32.Ssat16, OpCode32Sat16.Create);
|
||||||
|
SetA32("<<<<01100001xxxxxxxx11111111xxxx", InstName.Ssub8, InstEmit32.Ssub8, OpCode32AluReg.Create);
|
||||||
SetA32("<<<<00011000xxxx111111001001xxxx", InstName.Stl, InstEmit32.Stl, OpCode32MemStEx.Create);
|
SetA32("<<<<00011000xxxx111111001001xxxx", InstName.Stl, InstEmit32.Stl, OpCode32MemStEx.Create);
|
||||||
SetA32("<<<<00011100xxxx111111001001xxxx", InstName.Stlb, InstEmit32.Stlb, OpCode32MemStEx.Create);
|
SetA32("<<<<00011100xxxx111111001001xxxx", InstName.Stlb, InstEmit32.Stlb, OpCode32MemStEx.Create);
|
||||||
SetA32("<<<<00011000xxxxxxxx11101001xxxx", InstName.Stlex, InstEmit32.Stlex, OpCode32MemStEx.Create);
|
SetA32("<<<<00011000xxxxxxxx11101001xxxx", InstName.Stlex, InstEmit32.Stlex, OpCode32MemStEx.Create);
|
||||||
@@ -776,9 +797,11 @@ namespace ARMeilleure.Decoders
|
|||||||
SetA32("<<<<00010011xxxx0000xxxxxxx0xxxx", InstName.Teq, InstEmit32.Teq, OpCode32AluRsImm.Create);
|
SetA32("<<<<00010011xxxx0000xxxxxxx0xxxx", InstName.Teq, InstEmit32.Teq, OpCode32AluRsImm.Create);
|
||||||
SetA32("<<<<00010011xxxx0000xxxx0xx1xxxx", InstName.Teq, InstEmit32.Teq, OpCode32AluRsReg.Create);
|
SetA32("<<<<00010011xxxx0000xxxx0xx1xxxx", InstName.Teq, InstEmit32.Teq, OpCode32AluRsReg.Create);
|
||||||
SetA32("<<<<0111111111111101111011111110", InstName.Trap, InstEmit32.Trap, OpCode32Exception.Create);
|
SetA32("<<<<0111111111111101111011111110", InstName.Trap, InstEmit32.Trap, OpCode32Exception.Create);
|
||||||
|
SetA32("<<<<0011001000001111000000010010", InstName.Tsb, InstEmit32.Nop, OpCode32.Create); // Trace Synchronization Barrier (FEAT_TRF)
|
||||||
SetA32("<<<<00110001xxxx0000xxxxxxxxxxxx", InstName.Tst, InstEmit32.Tst, OpCode32AluImm.Create);
|
SetA32("<<<<00110001xxxx0000xxxxxxxxxxxx", InstName.Tst, InstEmit32.Tst, OpCode32AluImm.Create);
|
||||||
SetA32("<<<<00010001xxxx0000xxxxxxx0xxxx", InstName.Tst, InstEmit32.Tst, OpCode32AluRsImm.Create);
|
SetA32("<<<<00010001xxxx0000xxxxxxx0xxxx", InstName.Tst, InstEmit32.Tst, OpCode32AluRsImm.Create);
|
||||||
SetA32("<<<<00010001xxxx0000xxxx0xx1xxxx", InstName.Tst, InstEmit32.Tst, OpCode32AluRsReg.Create);
|
SetA32("<<<<00010001xxxx0000xxxx0xx1xxxx", InstName.Tst, InstEmit32.Tst, OpCode32AluRsReg.Create);
|
||||||
|
SetA32("<<<<01100101xxxxxxxx11111001xxxx", InstName.Uadd8, InstEmit32.Uadd8, OpCode32AluReg.Create);
|
||||||
SetA32("<<<<0111111xxxxxxxxxxxxxx101xxxx", InstName.Ubfx, InstEmit32.Ubfx, OpCode32AluBf.Create);
|
SetA32("<<<<0111111xxxxxxxxxxxxxx101xxxx", InstName.Ubfx, InstEmit32.Ubfx, OpCode32AluBf.Create);
|
||||||
SetA32("<<<<01110011xxxx1111xxxx0001xxxx", InstName.Udiv, InstEmit32.Udiv, OpCode32AluMla.Create);
|
SetA32("<<<<01110011xxxx1111xxxx0001xxxx", InstName.Udiv, InstEmit32.Udiv, OpCode32AluMla.Create);
|
||||||
SetA32("<<<<01100111xxxxxxxx11111001xxxx", InstName.Uhadd8, InstEmit32.Uhadd8, OpCode32AluReg.Create);
|
SetA32("<<<<01100111xxxxxxxx11111001xxxx", InstName.Uhadd8, InstEmit32.Uhadd8, OpCode32AluReg.Create);
|
||||||
@@ -788,207 +811,237 @@ namespace ARMeilleure.Decoders
|
|||||||
SetA32("<<<<0000100xxxxxxxxxxxxx1001xxxx", InstName.Umull, InstEmit32.Umull, OpCode32AluUmull.Create);
|
SetA32("<<<<0000100xxxxxxxxxxxxx1001xxxx", InstName.Umull, InstEmit32.Umull, OpCode32AluUmull.Create);
|
||||||
SetA32("<<<<0110111xxxxxxxxxxxxxxx01xxxx", InstName.Usat, InstEmit32.Usat, OpCode32Sat.Create);
|
SetA32("<<<<0110111xxxxxxxxxxxxxxx01xxxx", InstName.Usat, InstEmit32.Usat, OpCode32Sat.Create);
|
||||||
SetA32("<<<<01101110xxxxxxxx11110011xxxx", InstName.Usat16, InstEmit32.Usat16, OpCode32Sat16.Create);
|
SetA32("<<<<01101110xxxxxxxx11110011xxxx", InstName.Usat16, InstEmit32.Usat16, OpCode32Sat16.Create);
|
||||||
|
SetA32("<<<<01100101xxxxxxxx11111111xxxx", InstName.Usub8, InstEmit32.Usub8, OpCode32AluReg.Create);
|
||||||
SetA32("<<<<01101110xxxxxxxxxx000111xxxx", InstName.Uxtb, InstEmit32.Uxtb, OpCode32AluUx.Create);
|
SetA32("<<<<01101110xxxxxxxxxx000111xxxx", InstName.Uxtb, InstEmit32.Uxtb, OpCode32AluUx.Create);
|
||||||
SetA32("<<<<01101100xxxxxxxxxx000111xxxx", InstName.Uxtb16, InstEmit32.Uxtb16, OpCode32AluUx.Create);
|
SetA32("<<<<01101100xxxxxxxxxx000111xxxx", InstName.Uxtb16, InstEmit32.Uxtb16, OpCode32AluUx.Create);
|
||||||
SetA32("<<<<01101111xxxxxxxxxx000111xxxx", InstName.Uxth, InstEmit32.Uxth, OpCode32AluUx.Create);
|
SetA32("<<<<01101111xxxxxxxxxx000111xxxx", InstName.Uxth, InstEmit32.Uxth, OpCode32AluUx.Create);
|
||||||
|
SetA32("<<<<0011001000001111000000000010", InstName.Wfe, InstEmit32.Nop, OpCode32.Create);
|
||||||
|
SetA32("<<<<0011001000001111000000000011", InstName.Wfi, InstEmit32.Nop, OpCode32.Create);
|
||||||
|
SetA32("<<<<0011001000001111000000000001", InstName.Yield, InstEmit32.Nop, OpCode32.Create);
|
||||||
|
|
||||||
// FP & SIMD
|
// VFP
|
||||||
SetA32("111100111x110000xxx0001101x0xxx0", InstName.Aesd_V, InstEmit32.Aesd_V, OpCode32Simd.Create);
|
SetVfp("<<<<11101x110000xxxx101x11x0xxxx", InstName.Vabs, InstEmit32.Vabs_S, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
|
||||||
SetA32("111100111x110000xxx0001100x0xxx0", InstName.Aese_V, InstEmit32.Aese_V, OpCode32Simd.Create);
|
SetVfp("<<<<11100x11xxxxxxxx101xx0x0xxxx", InstName.Vadd, InstEmit32.Vadd_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
SetA32("111100111x110000xxx0001111x0xxx0", InstName.Aesimc_V, InstEmit32.Aesimc_V, OpCode32Simd.Create);
|
SetVfp("<<<<11101x11010xxxxx101x01x0xxxx", InstName.Vcmp, InstEmit32.Vcmp, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
|
||||||
SetA32("111100111x110000xxx0001110x0xxx0", InstName.Aesmc_V, InstEmit32.Aesmc_V, OpCode32Simd.Create);
|
SetVfp("<<<<11101x11010xxxxx101x11x0xxxx", InstName.Vcmpe, InstEmit32.Vcmpe, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
|
||||||
SetA32("111100110x00xxx0xxx01100x1x0xxx0", InstName.Sha256h_V, InstEmit32.Sha256h_V, OpCode32SimdReg.Create);
|
SetVfp("<<<<11101x110111xxxx101x11x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FD, OpCode32SimdS.Create, OpCode32SimdS.CreateT32); // FP 32 and 64, scalar.
|
||||||
SetA32("111100110x01xxx0xxx01100x1x0xxx0", InstName.Sha256h2_V, InstEmit32.Sha256h2_V, OpCode32SimdReg.Create);
|
SetVfp("<<<<11101x11110xxxxx101x11x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FI, OpCode32SimdCvtFI.Create, OpCode32SimdCvtFI.CreateT32); // FP32 to int.
|
||||||
SetA32("111100111x111010xxx0001111x0xxx0", InstName.Sha256su0_V, InstEmit32.Sha256su0_V, OpCode32Simd.Create);
|
SetVfp("<<<<11101x111000xxxx101xx1x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FI, OpCode32SimdCvtFI.Create, OpCode32SimdCvtFI.CreateT32); // Int to FP32.
|
||||||
SetA32("111100110x10xxx0xxx01100x1x0xxx0", InstName.Sha256su1_V, InstEmit32.Sha256su1_V, OpCode32SimdReg.Create);
|
SetVfp("111111101x1111xxxxxx101xx1x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_RM, OpCode32SimdCvtFI.Create, OpCode32SimdCvtFI.CreateT32); // The many FP32 to int encodings (fp).
|
||||||
SetA32("1111001x0x<<xxxxxxxx0111xxx0xxxx", InstName.Vabd, InstEmit32.Vabd_I, OpCode32SimdReg.Create);
|
SetVfp("<<<<11101x00xxxxxxxx101xx0x0xxxx", InstName.Vdiv, InstEmit32.Vdiv_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
SetA32("1111001x1x<<xxxxxxxx0111x0x0xxxx", InstName.Vabdl, InstEmit32.Vabdl_I, OpCode32SimdRegLong.Create);
|
SetVfp("<<<<11101xx0xxxxxxxx1011x0x10000", InstName.Vdup, InstEmit32.Vdup, OpCode32SimdDupGP.Create, OpCode32SimdDupGP.CreateT32);
|
||||||
SetA32("<<<<11101x110000xxxx101x11x0xxxx", InstName.Vabs, InstEmit32.Vabs_S, OpCode32SimdS.Create);
|
SetVfp("<<<<11101x10xxxxxxxx101xx0x0xxxx", InstName.Vfma, InstEmit32.Vfma_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
SetA32("111100111x11<<01xxxx00110xx0xxxx", InstName.Vabs, InstEmit32.Vabs_V, OpCode32SimdCmpZ.Create);
|
SetVfp("<<<<11101x10xxxxxxxx101xx1x0xxxx", InstName.Vfms, InstEmit32.Vfms_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
SetA32("111100111x111001xxxx01110xx0xxxx", InstName.Vabs, InstEmit32.Vabs_V, OpCode32SimdCmpZ.Create);
|
SetVfp("<<<<11101x01xxxxxxxx101xx1x0xxxx", InstName.Vfnma, InstEmit32.Vfnma_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
SetA32("111100100xxxxxxxxxxx1000xxx0xxxx", InstName.Vadd, InstEmit32.Vadd_I, OpCode32SimdReg.Create);
|
SetVfp("<<<<11101x01xxxxxxxx101xx0x0xxxx", InstName.Vfnms, InstEmit32.Vfnms_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
SetA32("<<<<11100x11xxxxxxxx101xx0x0xxxx", InstName.Vadd, InstEmit32.Vadd_S, OpCode32SimdRegS.Create);
|
SetVfp("<<<<11001x01xxxxxxxx1011xxxxxxx0", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create, OpCode32SimdMemMult.CreateT32);
|
||||||
SetA32("111100100x00xxxxxxxx1101xxx0xxxx", InstName.Vadd, InstEmit32.Vadd_V, OpCode32SimdReg.Create);
|
SetVfp("<<<<11001x11xxxxxxxx1011xxxxxxx0", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create, OpCode32SimdMemMult.CreateT32);
|
||||||
SetA32("1111001x1x<<xxxxxxx00000x0x0xxxx", InstName.Vaddl, InstEmit32.Vaddl_I, OpCode32SimdRegLong.Create);
|
SetVfp("<<<<11010x11xxxxxxxx1011xxxxxxx0", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create, OpCode32SimdMemMult.CreateT32);
|
||||||
SetA32("1111001x1x<<xxxxxxx00001x0x0xxxx", InstName.Vaddw, InstEmit32.Vaddw_I, OpCode32SimdRegWide.Create);
|
SetVfp("<<<<11001x01xxxxxxxx1010xxxxxxxx", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create, OpCode32SimdMemMult.CreateT32);
|
||||||
SetA32("111100100x00xxxxxxxx0001xxx1xxxx", InstName.Vand, InstEmit32.Vand_I, OpCode32SimdBinary.Create);
|
SetVfp("<<<<11001x11xxxxxxxx1010xxxxxxxx", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create, OpCode32SimdMemMult.CreateT32);
|
||||||
SetA32("111100100x01xxxxxxxx0001xxx1xxxx", InstName.Vbic, InstEmit32.Vbic_I, OpCode32SimdBinary.Create);
|
SetVfp("<<<<11010x11xxxxxxxx1010xxxxxxxx", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create, OpCode32SimdMemMult.CreateT32);
|
||||||
SetA32("1111001x1x000xxxxxxx<<x10x11xxxx", InstName.Vbic, InstEmit32.Vbic_II, OpCode32SimdImm.Create);
|
SetVfp("<<<<1101xx01xxxxxxxx101xxxxxxxxx", InstName.Vldr, InstEmit32.Vldr, OpCode32SimdMemImm.Create, OpCode32SimdMemImm.CreateT32);
|
||||||
SetA32("111100110x11xxxxxxxx0001xxx1xxxx", InstName.Vbif, InstEmit32.Vbif, OpCode32SimdBinary.Create);
|
SetVfp("111111101x00xxxxxxxx10>>x0x0xxxx", InstName.Vmaxnm, InstEmit32.Vmaxnm_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
SetA32("111100110x10xxxxxxxx0001xxx1xxxx", InstName.Vbit, InstEmit32.Vbit, OpCode32SimdBinary.Create);
|
SetVfp("111111101x00xxxxxxxx10>>x1x0xxxx", InstName.Vminnm, InstEmit32.Vminnm_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
SetA32("111100110x01xxxxxxxx0001xxx1xxxx", InstName.Vbsl, InstEmit32.Vbsl, OpCode32SimdBinary.Create);
|
SetVfp("<<<<11100x00xxxxxxxx101xx0x0xxxx", InstName.Vmla, InstEmit32.Vmla_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
SetA32("111100110x<<xxxxxxxx1000xxx1xxxx", InstName.Vceq, InstEmit32.Vceq_I, OpCode32SimdReg.Create);
|
SetVfp("<<<<11100x00xxxxxxxx101xx1x0xxxx", InstName.Vmls, InstEmit32.Vmls_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
SetA32("111100100x00xxxxxxxx1110xxx0xxxx", InstName.Vceq, InstEmit32.Vceq_V, OpCode32SimdReg.Create);
|
SetVfp("<<<<11100xx0xxxxxxxx1011xxx10000", InstName.Vmov, InstEmit32.Vmov_G1, OpCode32SimdMovGpElem.Create, OpCode32SimdMovGpElem.CreateT32); // From gen purpose.
|
||||||
SetA32("111100111x11xx01xxxx0x010xx0xxxx", InstName.Vceq, InstEmit32.Vceq_Z, OpCode32SimdCmpZ.Create);
|
SetVfp("<<<<1110xxx1xxxxxxxx1011xxx10000", InstName.Vmov, InstEmit32.Vmov_G1, OpCode32SimdMovGpElem.Create, OpCode32SimdMovGpElem.CreateT32); // To gen purpose.
|
||||||
SetA32("1111001x0x<<xxxxxxxx0011xxx1xxxx", InstName.Vcge, InstEmit32.Vcge_I, OpCode32SimdReg.Create);
|
SetVfp("<<<<1100010xxxxxxxxx101000x1xxxx", InstName.Vmov, InstEmit32.Vmov_G2, OpCode32SimdMovGpDouble.Create, OpCode32SimdMovGpDouble.CreateT32); // To/from gen purpose x2 and single precision x2.
|
||||||
SetA32("111100110x00xxxxxxxx1110xxx0xxxx", InstName.Vcge, InstEmit32.Vcge_V, OpCode32SimdReg.Create);
|
SetVfp("<<<<1100010xxxxxxxxx101100x1xxxx", InstName.Vmov, InstEmit32.Vmov_GD, OpCode32SimdMovGpDouble.Create, OpCode32SimdMovGpDouble.CreateT32); // To/from gen purpose x2 and double precision.
|
||||||
SetA32("111100111x11xx01xxxx0x001xx0xxxx", InstName.Vcge, InstEmit32.Vcge_Z, OpCode32SimdCmpZ.Create);
|
SetVfp("<<<<1110000xxxxxxxxx1010x0010000", InstName.Vmov, InstEmit32.Vmov_GS, OpCode32SimdMovGp.Create, OpCode32SimdMovGp.CreateT32); // To/from gen purpose and single precision.
|
||||||
SetA32("1111001x0x<<xxxxxxxx0011xxx0xxxx", InstName.Vcgt, InstEmit32.Vcgt_I, OpCode32SimdReg.Create);
|
SetVfp("<<<<11101x11xxxxxxxx101x0000xxxx", InstName.Vmov, InstEmit32.Vmov_I, OpCode32SimdImm44.Create, OpCode32SimdImm44.CreateT32); // Scalar f16/32/64 based on size 01 10 11.
|
||||||
SetA32("111100110x10xxxxxxxx1110xxx0xxxx", InstName.Vcgt, InstEmit32.Vcgt_V, OpCode32SimdReg.Create);
|
SetVfp("<<<<11101x110000xxxx101x01x0xxxx", InstName.Vmov, InstEmit32.Vmov_S, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
|
||||||
SetA32("111100111x11xx01xxxx0x000xx0xxxx", InstName.Vcgt, InstEmit32.Vcgt_Z, OpCode32SimdCmpZ.Create);
|
SetVfp("<<<<11101111xxxxxxxx101000010000", InstName.Vmrs, InstEmit32.Vmrs, OpCode32SimdSpecial.Create, OpCode32SimdSpecial.CreateT32);
|
||||||
SetA32("111100111x11xx01xxxx0x011xx0xxxx", InstName.Vcle, InstEmit32.Vcle_Z, OpCode32SimdCmpZ.Create);
|
SetVfp("<<<<11101110xxxxxxxx101000010000", InstName.Vmsr, InstEmit32.Vmsr, OpCode32SimdSpecial.Create, OpCode32SimdSpecial.CreateT32);
|
||||||
SetA32("111100111x11xx01xxxx0x100xx0xxxx", InstName.Vclt, InstEmit32.Vclt_Z, OpCode32SimdCmpZ.Create);
|
SetVfp("<<<<11100x10xxxxxxxx101xx0x0xxxx", InstName.Vmul, InstEmit32.Vmul_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
SetA32("<<<<11101x11010xxxxx101x01x0xxxx", InstName.Vcmp, InstEmit32.Vcmp, OpCode32SimdS.Create);
|
SetVfp("<<<<11101x110001xxxx101x01x0xxxx", InstName.Vneg, InstEmit32.Vneg_S, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
|
||||||
SetA32("<<<<11101x11010xxxxx101x11x0xxxx", InstName.Vcmpe, InstEmit32.Vcmpe, OpCode32SimdS.Create);
|
SetVfp("<<<<11100x01xxxxxxxx101xx1x0xxxx", InstName.Vnmla, InstEmit32.Vnmla_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
SetA32("111100111x110000xxxx01010xx0xxxx", InstName.Vcnt, InstEmit32.Vcnt, OpCode32SimdCmpZ.Create);
|
SetVfp("<<<<11100x01xxxxxxxx101xx0x0xxxx", InstName.Vnmls, InstEmit32.Vnmls_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
SetA32("<<<<11101x110111xxxx101x11x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FD, OpCode32SimdS.Create); // FP 32 and 64, scalar.
|
SetVfp("<<<<11100x10xxxxxxxx101xx1x0xxxx", InstName.Vnmul, InstEmit32.Vnmul_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
SetA32("<<<<11101x11110xxxxx101x11x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FI, OpCode32SimdCvtFI.Create); // FP32 to int.
|
SetVfp("111111101x1110xxxxxx101x01x0xxxx", InstName.Vrint, InstEmit32.Vrint_RM, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
|
||||||
SetA32("<<<<11101x111000xxxx101xx1x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FI, OpCode32SimdCvtFI.Create); // Int to FP32.
|
SetVfp("<<<<11101x110110xxxx101x11x0xxxx", InstName.Vrint, InstEmit32.Vrint_Z, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
|
||||||
SetA32("111111101x1111xxxxxx101xx1x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_RM, OpCode32SimdCvtFI.Create); // The many FP32 to int encodings (fp).
|
SetVfp("<<<<11101x110111xxxx101x01x0xxxx", InstName.Vrintx, InstEmit32.Vrintx_S, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
|
||||||
SetA32("111100111x111011xxxx011xxxx0xxxx", InstName.Vcvt, InstEmit32.Vcvt_V, OpCode32SimdCmpZ.Create); // FP and integer, vector.
|
SetVfp("<<<<11101x110001xxxx101x11x0xxxx", InstName.Vsqrt, InstEmit32.Vsqrt_S, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
|
||||||
SetA32("<<<<11101x00xxxxxxxx101xx0x0xxxx", InstName.Vdiv, InstEmit32.Vdiv_S, OpCode32SimdRegS.Create);
|
SetVfp("111111100xxxxxxxxxxx101xx0x0xxxx", InstName.Vsel, InstEmit32.Vsel, OpCode32SimdSel.Create, OpCode32SimdSel.CreateT32);
|
||||||
SetA32("<<<<11101xx0xxxxxxxx1011x0x10000", InstName.Vdup, InstEmit32.Vdup, OpCode32SimdDupGP.Create);
|
SetVfp("<<<<11001x00xxxxxxxx1011xxxxxxx0", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create, OpCode32SimdMemMult.CreateT32);
|
||||||
SetA32("111100111x11xxxxxxxx11000xx0xxxx", InstName.Vdup, InstEmit32.Vdup_1, OpCode32SimdDupElem.Create);
|
SetVfp("<<<<11001x10xxxxxxxx1011xxxxxxx0", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create, OpCode32SimdMemMult.CreateT32);
|
||||||
SetA32("111100110x00xxxxxxxx0001xxx1xxxx", InstName.Veor, InstEmit32.Veor_I, OpCode32SimdBinary.Create);
|
SetVfp("<<<<11010x10xxxxxxxx1011xxxxxxx0", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create, OpCode32SimdMemMult.CreateT32);
|
||||||
SetA32("111100101x11xxxxxxxxxxxxxxx0xxxx", InstName.Vext, InstEmit32.Vext, OpCode32SimdExt.Create);
|
SetVfp("<<<<11001x00xxxxxxxx1010xxxxxxxx", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create, OpCode32SimdMemMult.CreateT32);
|
||||||
SetA32("<<<<11101x10xxxxxxxx101xx0x0xxxx", InstName.Vfma, InstEmit32.Vfma_S, OpCode32SimdRegS.Create);
|
SetVfp("<<<<11001x10xxxxxxxx1010xxxxxxxx", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create, OpCode32SimdMemMult.CreateT32);
|
||||||
SetA32("111100100x00xxxxxxxx1100xxx1xxxx", InstName.Vfma, InstEmit32.Vfma_V, OpCode32SimdReg.Create);
|
SetVfp("<<<<11010x10xxxxxxxx1010xxxxxxxx", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create, OpCode32SimdMemMult.CreateT32);
|
||||||
SetA32("<<<<11101x10xxxxxxxx101xx1x0xxxx", InstName.Vfms, InstEmit32.Vfms_S, OpCode32SimdRegS.Create);
|
SetVfp("<<<<1101xx00xxxxxxxx101xxxxxxxxx", InstName.Vstr, InstEmit32.Vstr, OpCode32SimdMemImm.Create, OpCode32SimdMemImm.CreateT32);
|
||||||
SetA32("111100100x10xxxxxxxx1100xxx1xxxx", InstName.Vfms, InstEmit32.Vfms_V, OpCode32SimdReg.Create);
|
SetVfp("<<<<11100x11xxxxxxxx101xx1x0xxxx", InstName.Vsub, InstEmit32.Vsub_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
SetA32("<<<<11101x01xxxxxxxx101xx1x0xxxx", InstName.Vfnma, InstEmit32.Vfnma_S, OpCode32SimdRegS.Create);
|
|
||||||
SetA32("<<<<11101x01xxxxxxxx101xx0x0xxxx", InstName.Vfnms, InstEmit32.Vfnms_S, OpCode32SimdRegS.Create);
|
// ASIMD
|
||||||
SetA32("1111001x0x<<xxxxxxxx0000xxx0xxxx", InstName.Vhadd, InstEmit32.Vhadd, OpCode32SimdReg.Create);
|
SetAsimd("111100111x110000xxx0001101x0xxx0", InstName.Aesd_V, InstEmit32.Aesd_V, OpCode32Simd.Create, OpCode32Simd.CreateT32);
|
||||||
SetA32("111101001x10xxxxxxxxxx00xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, OpCode32SimdMemSingle.Create);
|
SetAsimd("111100111x110000xxx0001100x0xxx0", InstName.Aese_V, InstEmit32.Aese_V, OpCode32Simd.Create, OpCode32Simd.CreateT32);
|
||||||
SetA32("111101000x10xxxxxxxx0111xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, OpCode32SimdMemPair.Create); // Regs = 1.
|
SetAsimd("111100111x110000xxx0001111x0xxx0", InstName.Aesimc_V, InstEmit32.Aesimc_V, OpCode32Simd.Create, OpCode32Simd.CreateT32);
|
||||||
SetA32("111101000x10xxxxxxxx1010xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, OpCode32SimdMemPair.Create); // Regs = 2.
|
SetAsimd("111100111x110000xxx0001110x0xxx0", InstName.Aesmc_V, InstEmit32.Aesmc_V, OpCode32Simd.Create, OpCode32Simd.CreateT32);
|
||||||
SetA32("111101000x10xxxxxxxx0110xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, OpCode32SimdMemPair.Create); // Regs = 3.
|
SetAsimd("111100110x00xxx0xxx01100x1x0xxx0", InstName.Sha256h_V, InstEmit32.Sha256h_V, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("111101000x10xxxxxxxx0010xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, OpCode32SimdMemPair.Create); // Regs = 4.
|
SetAsimd("111100110x01xxx0xxx01100x1x0xxx0", InstName.Sha256h2_V, InstEmit32.Sha256h2_V, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("111101001x10xxxxxxxxxx01xxxxxxxx", InstName.Vld2, InstEmit32.Vld2, OpCode32SimdMemSingle.Create);
|
SetAsimd("111100111x111010xxx0001111x0xxx0", InstName.Sha256su0_V, InstEmit32.Sha256su0_V, OpCode32Simd.Create, OpCode32Simd.CreateT32);
|
||||||
SetA32("111101000x10xxxxxxxx100xxxxxxxxx", InstName.Vld2, InstEmit32.Vld2, OpCode32SimdMemPair.Create); // Regs = 1, inc = 1/2 (itype).
|
SetAsimd("111100110x10xxx0xxx01100x1x0xxx0", InstName.Sha256su1_V, InstEmit32.Sha256su1_V, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("111101000x10xxxxxxxx0011xxxxxxxx", InstName.Vld2, InstEmit32.Vld2, OpCode32SimdMemPair.Create); // Regs = 2, inc = 2.
|
SetAsimd("1111001x0x<<xxxxxxxx0111xxx0xxxx", InstName.Vabd, InstEmit32.Vabd_I, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("111101001x10xxxxxxxxxx10xxxxxxxx", InstName.Vld3, InstEmit32.Vld3, OpCode32SimdMemSingle.Create);
|
SetAsimd("1111001x1x<<xxxxxxxx0111x0x0xxxx", InstName.Vabdl, InstEmit32.Vabdl_I, OpCode32SimdRegLong.Create, OpCode32SimdRegLong.CreateT32);
|
||||||
SetA32("111101000x10xxxxxxxx010xxxxxxxxx", InstName.Vld3, InstEmit32.Vld3, OpCode32SimdMemPair.Create); // Inc = 1/2 (itype).
|
SetAsimd("111100111x11<<01xxxx00110xx0xxxx", InstName.Vabs, InstEmit32.Vabs_V, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32);
|
||||||
SetA32("111101001x10xxxxxxxxxx11xxxxxxxx", InstName.Vld4, InstEmit32.Vld4, OpCode32SimdMemSingle.Create);
|
SetAsimd("111100111x111001xxxx01110xx0xxxx", InstName.Vabs, InstEmit32.Vabs_V, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32);
|
||||||
SetA32("111101000x10xxxxxxxx000xxxxxxxxx", InstName.Vld4, InstEmit32.Vld4, OpCode32SimdMemPair.Create); // Inc = 1/2 (itype).
|
SetAsimd("111100100xxxxxxxxxxx1000xxx0xxxx", InstName.Vadd, InstEmit32.Vadd_I, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("<<<<11001x01xxxxxxxx1011xxxxxxx0", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create);
|
SetAsimd("111100100x00xxxxxxxx1101xxx0xxxx", InstName.Vadd, InstEmit32.Vadd_V, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("<<<<11001x11xxxxxxxx1011xxxxxxx0", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create);
|
SetAsimd("1111001x1x<<xxxxxxx00000x0x0xxxx", InstName.Vaddl, InstEmit32.Vaddl_I, OpCode32SimdRegLong.Create, OpCode32SimdRegLong.CreateT32);
|
||||||
SetA32("<<<<11010x11xxxxxxxx1011xxxxxxx0", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create);
|
SetAsimd("1111001x1x<<xxxxxxx00001x0x0xxxx", InstName.Vaddw, InstEmit32.Vaddw_I, OpCode32SimdRegWide.Create, OpCode32SimdRegWide.CreateT32);
|
||||||
SetA32("<<<<11001x01xxxxxxxx1010xxxxxxxx", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create);
|
SetAsimd("111100100x00xxxxxxxx0001xxx1xxxx", InstName.Vand, InstEmit32.Vand_I, OpCode32SimdBinary.Create, OpCode32SimdBinary.CreateT32);
|
||||||
SetA32("<<<<11001x11xxxxxxxx1010xxxxxxxx", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create);
|
SetAsimd("111100100x01xxxxxxxx0001xxx1xxxx", InstName.Vbic, InstEmit32.Vbic_I, OpCode32SimdBinary.Create, OpCode32SimdBinary.CreateT32);
|
||||||
SetA32("<<<<11010x11xxxxxxxx1010xxxxxxxx", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create);
|
SetAsimd("1111001x1x000xxxxxxx<<x10x11xxxx", InstName.Vbic, InstEmit32.Vbic_II, OpCode32SimdImm.Create, OpCode32SimdImm.CreateT32);
|
||||||
SetA32("<<<<1101xx01xxxxxxxx101xxxxxxxxx", InstName.Vldr, InstEmit32.Vldr, OpCode32SimdMemImm.Create);
|
SetAsimd("111100110x11xxxxxxxx0001xxx1xxxx", InstName.Vbif, InstEmit32.Vbif, OpCode32SimdBinary.Create, OpCode32SimdBinary.CreateT32);
|
||||||
SetA32("1111001x0x<<xxxxxxxx0110xxx0xxxx", InstName.Vmax, InstEmit32.Vmax_I, OpCode32SimdReg.Create);
|
SetAsimd("111100110x10xxxxxxxx0001xxx1xxxx", InstName.Vbit, InstEmit32.Vbit, OpCode32SimdBinary.Create, OpCode32SimdBinary.CreateT32);
|
||||||
SetA32("111100100x00xxxxxxxx1111xxx0xxxx", InstName.Vmax, InstEmit32.Vmax_V, OpCode32SimdReg.Create);
|
SetAsimd("111100110x01xxxxxxxx0001xxx1xxxx", InstName.Vbsl, InstEmit32.Vbsl, OpCode32SimdBinary.Create, OpCode32SimdBinary.CreateT32);
|
||||||
SetA32("1111001x0x<<xxxxxxxx0110xxx1xxxx", InstName.Vmin, InstEmit32.Vmin_I, OpCode32SimdReg.Create);
|
SetAsimd("111100110x<<xxxxxxxx1000xxx1xxxx", InstName.Vceq, InstEmit32.Vceq_I, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("111100100x10xxxxxxxx1111xxx0xxxx", InstName.Vmin, InstEmit32.Vmin_V, OpCode32SimdReg.Create);
|
SetAsimd("111100100x00xxxxxxxx1110xxx0xxxx", InstName.Vceq, InstEmit32.Vceq_V, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("111111101x00xxxxxxxx10>>x0x0xxxx", InstName.Vmaxnm, InstEmit32.Vmaxnm_S, OpCode32SimdRegS.Create);
|
SetAsimd("111100111x11xx01xxxx0x010xx0xxxx", InstName.Vceq, InstEmit32.Vceq_Z, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32);
|
||||||
SetA32("111100110x0xxxxxxxxx1111xxx1xxxx", InstName.Vmaxnm, InstEmit32.Vmaxnm_V, OpCode32SimdReg.Create);
|
SetAsimd("1111001x0x<<xxxxxxxx0011xxx1xxxx", InstName.Vcge, InstEmit32.Vcge_I, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("111111101x00xxxxxxxx10>>x1x0xxxx", InstName.Vminnm, InstEmit32.Vminnm_S, OpCode32SimdRegS.Create);
|
SetAsimd("111100110x00xxxxxxxx1110xxx0xxxx", InstName.Vcge, InstEmit32.Vcge_V, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("111100110x1xxxxxxxxx1111xxx1xxxx", InstName.Vminnm, InstEmit32.Vminnm_V, OpCode32SimdReg.Create);
|
SetAsimd("111100111x11xx01xxxx0x001xx0xxxx", InstName.Vcge, InstEmit32.Vcge_Z, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32);
|
||||||
SetA32("1111001x1x<<xxxxxxxx000xx1x0xxxx", InstName.Vmla, InstEmit32.Vmla_1, OpCode32SimdRegElem.Create);
|
SetAsimd("1111001x0x<<xxxxxxxx0011xxx0xxxx", InstName.Vcgt, InstEmit32.Vcgt_I, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("111100100xxxxxxxxxxx1001xxx0xxxx", InstName.Vmla, InstEmit32.Vmla_I, OpCode32SimdReg.Create);
|
SetAsimd("111100110x10xxxxxxxx1110xxx0xxxx", InstName.Vcgt, InstEmit32.Vcgt_V, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("<<<<11100x00xxxxxxxx101xx0x0xxxx", InstName.Vmla, InstEmit32.Vmla_S, OpCode32SimdRegS.Create);
|
SetAsimd("111100111x11xx01xxxx0x000xx0xxxx", InstName.Vcgt, InstEmit32.Vcgt_Z, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32);
|
||||||
SetA32("111100100x00xxxxxxxx1101xxx1xxxx", InstName.Vmla, InstEmit32.Vmla_V, OpCode32SimdReg.Create);
|
SetAsimd("111100111x11xx01xxxx0x011xx0xxxx", InstName.Vcle, InstEmit32.Vcle_Z, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32);
|
||||||
SetA32("1111001x1x<<xxxxxxx01000x0x0xxxx", InstName.Vmlal, InstEmit32.Vmlal_I, OpCode32SimdRegLong.Create);
|
SetAsimd("111100111x11xx01xxxx0x100xx0xxxx", InstName.Vclt, InstEmit32.Vclt_Z, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32);
|
||||||
SetA32("1111001x1x<<xxxxxxxx010xx1x0xxxx", InstName.Vmls, InstEmit32.Vmls_1, OpCode32SimdRegElem.Create);
|
SetAsimd("111100111x110000xxxx01010xx0xxxx", InstName.Vcnt, InstEmit32.Vcnt, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32);
|
||||||
SetA32("<<<<11100x00xxxxxxxx101xx1x0xxxx", InstName.Vmls, InstEmit32.Vmls_S, OpCode32SimdRegS.Create);
|
SetAsimd("111100111x111011xxxx011xxxx0xxxx", InstName.Vcvt, InstEmit32.Vcvt_V, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32); // FP and integer, vector.
|
||||||
SetA32("111100100x10xxxxxxxx1101xxx1xxxx", InstName.Vmls, InstEmit32.Vmls_V, OpCode32SimdReg.Create);
|
SetAsimd("111100111x11xxxxxxxx11000xx0xxxx", InstName.Vdup, InstEmit32.Vdup_1, OpCode32SimdDupElem.Create, OpCode32SimdDupElem.CreateT32);
|
||||||
SetA32("111100110xxxxxxxxxxx1001xxx0xxxx", InstName.Vmls, InstEmit32.Vmls_I, OpCode32SimdReg.Create);
|
SetAsimd("111100110x00xxxxxxxx0001xxx1xxxx", InstName.Veor, InstEmit32.Veor_I, OpCode32SimdBinary.Create, OpCode32SimdBinary.CreateT32);
|
||||||
SetA32("1111001x1x<<xxxxxxx01010x0x0xxxx", InstName.Vmlsl, InstEmit32.Vmlsl_I, OpCode32SimdRegLong.Create);
|
SetAsimd("111100101x11xxxxxxxxxxxxxxx0xxxx", InstName.Vext, InstEmit32.Vext, OpCode32SimdExt.Create, OpCode32SimdExt.CreateT32);
|
||||||
SetA32("<<<<11100xx0xxxxxxxx1011xxx10000", InstName.Vmov, InstEmit32.Vmov_G1, OpCode32SimdMovGpElem.Create); // From gen purpose.
|
SetAsimd("111100100x00xxxxxxxx1100xxx1xxxx", InstName.Vfma, InstEmit32.Vfma_V, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("<<<<1110xxx1xxxxxxxx1011xxx10000", InstName.Vmov, InstEmit32.Vmov_G1, OpCode32SimdMovGpElem.Create); // To gen purpose.
|
SetAsimd("111100100x10xxxxxxxx1100xxx1xxxx", InstName.Vfms, InstEmit32.Vfms_V, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("<<<<1100010xxxxxxxxx101000x1xxxx", InstName.Vmov, InstEmit32.Vmov_G2, OpCode32SimdMovGpDouble.Create); // To/from gen purpose x2 and single precision x2.
|
SetAsimd("1111001x0x<<xxxxxxxx0000xxx0xxxx", InstName.Vhadd, InstEmit32.Vhadd, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("<<<<1100010xxxxxxxxx101100x1xxxx", InstName.Vmov, InstEmit32.Vmov_GD, OpCode32SimdMovGpDouble.Create); // To/from gen purpose x2 and double precision.
|
SetAsimd("111101001x10xxxxxxxx0000xxx0xxxx", InstName.Vld1, InstEmit32.Vld1, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32);
|
||||||
SetA32("<<<<1110000xxxxxxxxx1010x0010000", InstName.Vmov, InstEmit32.Vmov_GS, OpCode32SimdMovGp.Create); // To/from gen purpose and single precision.
|
SetAsimd("111101001x10xxxxxxxx0100xx0xxxxx", InstName.Vld1, InstEmit32.Vld1, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32);
|
||||||
SetA32("1111001x1x000xxxxxxx0xx00x01xxxx", InstName.Vmov, InstEmit32.Vmov_I, OpCode32SimdImm.Create); // D/Q vector I32.
|
SetAsimd("111101001x10xxxxxxxx1000x000xxxx", InstName.Vld1, InstEmit32.Vld1, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32);
|
||||||
SetA32("<<<<11101x11xxxxxxxx101x0000xxxx", InstName.Vmov, InstEmit32.Vmov_I, OpCode32SimdImm44.Create); // Scalar f16/32/64 based on size 01 10 11.
|
SetAsimd("111101001x10xxxxxxxx1000x011xxxx", InstName.Vld1, InstEmit32.Vld1, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32);
|
||||||
SetA32("1111001x1x000xxxxxxx10x00x01xxxx", InstName.Vmov, InstEmit32.Vmov_I, OpCode32SimdImm.Create); // D/Q I16.
|
SetAsimd("111101001x10xxxxxxxx110000x0xxxx", InstName.Vld1, InstEmit32.Vld1, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32);
|
||||||
SetA32("1111001x1x000xxxxxxx11xx0x01xxxx", InstName.Vmov, InstEmit32.Vmov_I, OpCode32SimdImm.Create); // D/Q (dt - from cmode).
|
SetAsimd("111101001x10xxxxxxxx110001xxxxxx", InstName.Vld1, InstEmit32.Vld1, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32);
|
||||||
SetA32("1111001x1x000xxxxxxx11100x11xxxx", InstName.Vmov, InstEmit32.Vmov_I, OpCode32SimdImm.Create); // D/Q I64.
|
SetAsimd("111101001x10xxxxxxxx110010xxxxxx", InstName.Vld1, InstEmit32.Vld1, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32);
|
||||||
SetA32("<<<<11101x110000xxxx101x01x0xxxx", InstName.Vmov, InstEmit32.Vmov_S, OpCode32SimdS.Create);
|
SetAsimd("111101000x10xxxxxxxx0111xx0xxxxx", InstName.Vld1, InstEmit32.Vld1, OpCode32SimdMemPair.Create, OpCode32SimdMemPair.CreateT32); // Regs = 1.
|
||||||
SetA32("1111001x1x001000xxx0101000x1xxxx", InstName.Vmovl, InstEmit32.Vmovl, OpCode32SimdLong.Create);
|
SetAsimd("111101000x10xxxxxxxx1010xx<<xxxx", InstName.Vld1, InstEmit32.Vld1, OpCode32SimdMemPair.Create, OpCode32SimdMemPair.CreateT32); // Regs = 2.
|
||||||
SetA32("1111001x1x010000xxx0101000x1xxxx", InstName.Vmovl, InstEmit32.Vmovl, OpCode32SimdLong.Create);
|
SetAsimd("111101000x10xxxxxxxx0110xx0xxxxx", InstName.Vld1, InstEmit32.Vld1, OpCode32SimdMemPair.Create, OpCode32SimdMemPair.CreateT32); // Regs = 3.
|
||||||
SetA32("1111001x1x100000xxx0101000x1xxxx", InstName.Vmovl, InstEmit32.Vmovl, OpCode32SimdLong.Create);
|
SetAsimd("111101000x10xxxxxxxx0010xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, OpCode32SimdMemPair.Create, OpCode32SimdMemPair.CreateT32); // Regs = 4.
|
||||||
SetA32("111100111x11<<10xxxx001000x0xxx0", InstName.Vmovn, InstEmit32.Vmovn, OpCode32SimdMovn.Create);
|
SetAsimd("111101001x10xxxxxxxx0x01xxxxxxxx", InstName.Vld2, InstEmit32.Vld2, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32);
|
||||||
SetA32("<<<<11101111xxxxxxxx101000010000", InstName.Vmrs, InstEmit32.Vmrs, OpCode32SimdSpecial.Create);
|
SetAsimd("111101001x10xxxxxxxx1001xx0xxxxx", InstName.Vld2, InstEmit32.Vld2, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32);
|
||||||
SetA32("<<<<11101110xxxxxxxx101000010000", InstName.Vmsr, InstEmit32.Vmsr, OpCode32SimdSpecial.Create);
|
SetAsimd("111101001x10xxxxxxxx1101<<xxxxxx", InstName.Vld2, InstEmit32.Vld2, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32);
|
||||||
SetA32("1111001x1x<<xxxxxxxx100xx1x0xxxx", InstName.Vmul, InstEmit32.Vmul_1, OpCode32SimdRegElem.Create);
|
SetAsimd("111101000x10xxxxxxxx100x<<0xxxxx", InstName.Vld2, InstEmit32.Vld2, OpCode32SimdMemPair.Create, OpCode32SimdMemPair.CreateT32); // Regs = 1, inc = 1/2 (itype).
|
||||||
SetA32("111100100x<<xxxxxxxx1001xxx1xxxx", InstName.Vmul, InstEmit32.Vmul_I, OpCode32SimdReg.Create);
|
SetAsimd("111101000x10xxxxxxxx100x<<10xxxx", InstName.Vld2, InstEmit32.Vld2, OpCode32SimdMemPair.Create, OpCode32SimdMemPair.CreateT32); // Regs = 1, inc = 1/2 (itype).
|
||||||
SetA32("111100110x00xxxxxxxx1001xxx1xxxx", InstName.Vmul, InstEmit32.Vmul_I, OpCode32SimdReg.Create);
|
SetAsimd("111101000x10xxxxxxxx0011<<xxxxxx", InstName.Vld2, InstEmit32.Vld2, OpCode32SimdMemPair.Create, OpCode32SimdMemPair.CreateT32); // Regs = 2, inc = 2.
|
||||||
SetA32("<<<<11100x10xxxxxxxx101xx0x0xxxx", InstName.Vmul, InstEmit32.Vmul_S, OpCode32SimdRegS.Create);
|
SetAsimd("111101001x10xxxxxxxx0x10xxx0xxxx", InstName.Vld3, InstEmit32.Vld3, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32);
|
||||||
SetA32("111100110x00xxxxxxxx1101xxx1xxxx", InstName.Vmul, InstEmit32.Vmul_V, OpCode32SimdReg.Create);
|
SetAsimd("111101001x10xxxxxxxx1010xx00xxxx", InstName.Vld3, InstEmit32.Vld3, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32);
|
||||||
SetA32("1111001x1x<<xxxxxxx01010x1x0xxxx", InstName.Vmull, InstEmit32.Vmull_1, OpCode32SimdRegElemLong.Create);
|
SetAsimd("111101001x10xxxxxxxx1110<<x0xxxx", InstName.Vld3, InstEmit32.Vld3, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32);
|
||||||
SetA32("1111001x1x<<xxxxxxx01100x0x0xxxx", InstName.Vmull, InstEmit32.Vmull_I, OpCode32SimdRegLong.Create);
|
SetAsimd("111101000x10xxxxxxxx010x<<0xxxxx", InstName.Vld3, InstEmit32.Vld3, OpCode32SimdMemPair.Create, OpCode32SimdMemPair.CreateT32); // Inc = 1/2 (itype).
|
||||||
SetA32("111100101xx0xxxxxxx01110x0x0xxxx", InstName.Vmull, InstEmit32.Vmull_I, OpCode32SimdRegLong.Create); // P8/P64
|
SetAsimd("111101001x10xxxxxxxx0x11xxxxxxxx", InstName.Vld4, InstEmit32.Vld4, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32);
|
||||||
SetA32("111100111x110000xxxx01011xx0xxxx", InstName.Vmvn, InstEmit32.Vmvn_I, OpCode32SimdBinary.Create);
|
SetAsimd("111101001x10xxxxxxxx1011xx<<xxxx", InstName.Vld4, InstEmit32.Vld4, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32);
|
||||||
SetA32("1111001x1x000xxxxxxx0xx00x11xxxx", InstName.Vmvn, InstEmit32.Vmvn_II, OpCode32SimdImm.Create); // D/Q vector I32.
|
SetAsimd("111101001x10xxxxxxxx1111<<x>xxxx", InstName.Vld4, InstEmit32.Vld4, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32);
|
||||||
SetA32("1111001x1x000xxxxxxx10x00x11xxxx", InstName.Vmvn, InstEmit32.Vmvn_II, OpCode32SimdImm.Create);
|
SetAsimd("111101000x10xxxxxxxx000x<<xxxxxx", InstName.Vld4, InstEmit32.Vld4, OpCode32SimdMemPair.Create, OpCode32SimdMemPair.CreateT32); // Inc = 1/2 (itype).
|
||||||
SetA32("1111001x1x000xxxxxxx110x0x11xxxx", InstName.Vmvn, InstEmit32.Vmvn_II, OpCode32SimdImm.Create);
|
SetAsimd("1111001x0x<<xxxxxxxx0110xxx0xxxx", InstName.Vmax, InstEmit32.Vmax_I, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("<<<<11101x110001xxxx101x01x0xxxx", InstName.Vneg, InstEmit32.Vneg_S, OpCode32SimdS.Create);
|
SetAsimd("111100100x00xxxxxxxx1111xxx0xxxx", InstName.Vmax, InstEmit32.Vmax_V, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("111100111x11<<01xxxx00111xx0xxxx", InstName.Vneg, InstEmit32.Vneg_V, OpCode32SimdCmpZ.Create);
|
SetAsimd("1111001x0x<<xxxxxxxx0110xxx1xxxx", InstName.Vmin, InstEmit32.Vmin_I, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("111100111x111001xxxx01111xx0xxxx", InstName.Vneg, InstEmit32.Vneg_V, OpCode32SimdCmpZ.Create);
|
SetAsimd("111100100x10xxxxxxxx1111xxx0xxxx", InstName.Vmin, InstEmit32.Vmin_V, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("<<<<11100x01xxxxxxxx101xx1x0xxxx", InstName.Vnmla, InstEmit32.Vnmla_S, OpCode32SimdRegS.Create);
|
SetAsimd("111100110x0xxxxxxxxx1111xxx1xxxx", InstName.Vmaxnm, InstEmit32.Vmaxnm_V, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("<<<<11100x01xxxxxxxx101xx0x0xxxx", InstName.Vnmls, InstEmit32.Vnmls_S, OpCode32SimdRegS.Create);
|
SetAsimd("111100110x1xxxxxxxxx1111xxx1xxxx", InstName.Vminnm, InstEmit32.Vminnm_V, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("<<<<11100x10xxxxxxxx101xx1x0xxxx", InstName.Vnmul, InstEmit32.Vnmul_S, OpCode32SimdRegS.Create);
|
SetAsimd("1111001x1x<<xxxxxxxx000xx1x0xxxx", InstName.Vmla, InstEmit32.Vmla_1, OpCode32SimdRegElem.Create, OpCode32SimdRegElem.CreateT32);
|
||||||
SetA32("111100100x11xxxxxxxx0001xxx1xxxx", InstName.Vorn, InstEmit32.Vorn_I, OpCode32SimdBinary.Create);
|
SetAsimd("111100100xxxxxxxxxxx1001xxx0xxxx", InstName.Vmla, InstEmit32.Vmla_I, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("111100100x10xxxxxxxx0001xxx1xxxx", InstName.Vorr, InstEmit32.Vorr_I, OpCode32SimdBinary.Create);
|
SetAsimd("111100100x00xxxxxxxx1101xxx1xxxx", InstName.Vmla, InstEmit32.Vmla_V, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("1111001x1x000xxxxxxx<<x10x01xxxx", InstName.Vorr, InstEmit32.Vorr_II, OpCode32SimdImm.Create);
|
SetAsimd("1111001x1x<<xxxxxxx01000x0x0xxxx", InstName.Vmlal, InstEmit32.Vmlal_I, OpCode32SimdRegLong.Create, OpCode32SimdRegLong.CreateT32);
|
||||||
SetA32("111100100x<<xxxxxxxx1011x0x1xxxx", InstName.Vpadd, InstEmit32.Vpadd_I, OpCode32SimdReg.Create);
|
SetAsimd("1111001x1x<<xxxxxxxx010xx1x0xxxx", InstName.Vmls, InstEmit32.Vmls_1, OpCode32SimdRegElem.Create, OpCode32SimdRegElem.CreateT32);
|
||||||
SetA32("111100110x00xxxxxxxx1101x0x0xxxx", InstName.Vpadd, InstEmit32.Vpadd_V, OpCode32SimdReg.Create);
|
SetAsimd("111100100x10xxxxxxxx1101xxx1xxxx", InstName.Vmls, InstEmit32.Vmls_V, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("111100111x11<<00xxxx0010xxx0xxxx", InstName.Vpaddl, InstEmit32.Vpaddl, OpCode32SimdCmpZ.Create);
|
SetAsimd("111100110xxxxxxxxxxx1001xxx0xxxx", InstName.Vmls, InstEmit32.Vmls_I, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("1111001x0x<<xxxxxxxx1010x0x0xxxx", InstName.Vpmax, InstEmit32.Vpmax_I, OpCode32SimdReg.Create);
|
SetAsimd("1111001x1x<<xxxxxxx01010x0x0xxxx", InstName.Vmlsl, InstEmit32.Vmlsl_I, OpCode32SimdRegLong.Create, OpCode32SimdRegLong.CreateT32);
|
||||||
SetA32("111100110x00xxxxxxxx1111x0x0xxxx", InstName.Vpmax, InstEmit32.Vpmax_V, OpCode32SimdReg.Create);
|
SetAsimd("1111001x1x000xxxxxxx0xx00x01xxxx", InstName.Vmov, InstEmit32.Vmov_I, OpCode32SimdImm.Create, OpCode32SimdImm.CreateT32); // D/Q vector I32.
|
||||||
SetA32("1111001x0x<<xxxxxxxx1010x0x1xxxx", InstName.Vpmin, InstEmit32.Vpmin_I, OpCode32SimdReg.Create);
|
SetAsimd("1111001x1x000xxxxxxx10x00x01xxxx", InstName.Vmov, InstEmit32.Vmov_I, OpCode32SimdImm.Create, OpCode32SimdImm.CreateT32); // D/Q I16.
|
||||||
SetA32("111100110x10xxxxxxxx1111x0x0xxxx", InstName.Vpmin, InstEmit32.Vpmin_V, OpCode32SimdReg.Create);
|
SetAsimd("1111001x1x000xxxxxxx11xx0x01xxxx", InstName.Vmov, InstEmit32.Vmov_I, OpCode32SimdImm.Create, OpCode32SimdImm.CreateT32); // D/Q (dt - from cmode).
|
||||||
SetA32("1111001x0xxxxxxxxxxx0000xxx1xxxx", InstName.Vqadd, InstEmit32.Vqadd, OpCode32SimdReg.Create);
|
SetAsimd("1111001x1x000xxxxxxx11100x11xxxx", InstName.Vmov, InstEmit32.Vmov_I, OpCode32SimdImm.Create, OpCode32SimdImm.CreateT32); // D/Q I64.
|
||||||
SetA32("111100100x01xxxxxxxx1011xxx0xxxx", InstName.Vqdmulh, InstEmit32.Vqdmulh, OpCode32SimdReg.Create);
|
SetAsimd("1111001x1x001000xxx0101000x1xxxx", InstName.Vmovl, InstEmit32.Vmovl, OpCode32SimdLong.Create, OpCode32SimdLong.CreateT32);
|
||||||
SetA32("111100100x10xxxxxxxx1011xxx0xxxx", InstName.Vqdmulh, InstEmit32.Vqdmulh, OpCode32SimdReg.Create);
|
SetAsimd("1111001x1x010000xxx0101000x1xxxx", InstName.Vmovl, InstEmit32.Vmovl, OpCode32SimdLong.Create, OpCode32SimdLong.CreateT32);
|
||||||
SetA32("111100111x11<<10xxxx00101xx0xxx0", InstName.Vqmovn, InstEmit32.Vqmovn, OpCode32SimdMovn.Create);
|
SetAsimd("1111001x1x100000xxx0101000x1xxxx", InstName.Vmovl, InstEmit32.Vmovl, OpCode32SimdLong.Create, OpCode32SimdLong.CreateT32);
|
||||||
SetA32("111100111x11<<10xxxx001001x0xxx0", InstName.Vqmovun, InstEmit32.Vqmovun, OpCode32SimdMovn.Create);
|
SetAsimd("111100111x11<<10xxxx001000x0xxx0", InstName.Vmovn, InstEmit32.Vmovn, OpCode32SimdMovn.Create, OpCode32SimdMovn.CreateT32);
|
||||||
SetA32("1111001x1x>>>xxxxxxx100101x1xxx0", InstName.Vqrshrn, InstEmit32.Vqrshrn, OpCode32SimdShImmNarrow.Create);
|
SetAsimd("1111001x1x<<xxxxxxxx100xx1x0xxxx", InstName.Vmul, InstEmit32.Vmul_1, OpCode32SimdRegElem.Create, OpCode32SimdRegElem.CreateT32);
|
||||||
SetA32("111100111x>>>xxxxxxx100001x1xxx0", InstName.Vqrshrun, InstEmit32.Vqrshrun, OpCode32SimdShImmNarrow.Create);
|
SetAsimd("111100100x<<xxxxxxxx1001xxx1xxxx", InstName.Vmul, InstEmit32.Vmul_I, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("1111001x1x>>>xxxxxxx100100x1xxx0", InstName.Vqshrn, InstEmit32.Vqshrn, OpCode32SimdShImmNarrow.Create);
|
SetAsimd("111100110x00xxxxxxxx1001xxx1xxxx", InstName.Vmul, InstEmit32.Vmul_I, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("111100111x>>>xxxxxxx100000x1xxx0", InstName.Vqshrun, InstEmit32.Vqshrun, OpCode32SimdShImmNarrow.Create);
|
SetAsimd("111100110x00xxxxxxxx1101xxx1xxxx", InstName.Vmul, InstEmit32.Vmul_V, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("1111001x0xxxxxxxxxxx0010xxx1xxxx", InstName.Vqsub, InstEmit32.Vqsub, OpCode32SimdReg.Create);
|
SetAsimd("1111001x1x<<xxxxxxx01010x1x0xxxx", InstName.Vmull, InstEmit32.Vmull_1, OpCode32SimdRegElemLong.Create, OpCode32SimdRegElemLong.CreateT32);
|
||||||
SetA32("111100111x111011xxxx010x0xx0xxxx", InstName.Vrecpe, InstEmit32.Vrecpe, OpCode32SimdSqrte.Create);
|
SetAsimd("1111001x1x<<xxxxxxx01100x0x0xxxx", InstName.Vmull, InstEmit32.Vmull_I, OpCode32SimdRegLong.Create, OpCode32SimdRegLong.CreateT32);
|
||||||
SetA32("111100100x00xxxxxxxx1111xxx1xxxx", InstName.Vrecps, InstEmit32.Vrecps, OpCode32SimdReg.Create);
|
SetAsimd("111100101xx0xxxxxxx01110x0x0xxxx", InstName.Vmull, InstEmit32.Vmull_I, OpCode32SimdRegLong.Create, OpCode32SimdRegLong.CreateT32); // P8/P64
|
||||||
SetA32("111100111x11xx00xxxx000<<xx0xxxx", InstName.Vrev, InstEmit32.Vrev, OpCode32SimdRev.Create);
|
SetAsimd("111100111x110000xxxx01011xx0xxxx", InstName.Vmvn, InstEmit32.Vmvn_I, OpCode32SimdBinary.Create, OpCode32SimdBinary.CreateT32);
|
||||||
SetA32("1111001x0x<<xxxxxxxx0001xxx0xxxx", InstName.Vrhadd, InstEmit32.Vrhadd, OpCode32SimdReg.Create);
|
SetAsimd("1111001x1x000xxxxxxx0xx00x11xxxx", InstName.Vmvn, InstEmit32.Vmvn_II, OpCode32SimdImm.Create, OpCode32SimdImm.CreateT32); // D/Q vector I32.
|
||||||
SetA32("111111101x1110xxxxxx101x01x0xxxx", InstName.Vrint, InstEmit32.Vrint_RM, OpCode32SimdS.Create);
|
SetAsimd("1111001x1x000xxxxxxx10x00x11xxxx", InstName.Vmvn, InstEmit32.Vmvn_II, OpCode32SimdImm.Create, OpCode32SimdImm.CreateT32);
|
||||||
SetA32("<<<<11101x110110xxxx101x11x0xxxx", InstName.Vrint, InstEmit32.Vrint_Z, OpCode32SimdS.Create);
|
SetAsimd("1111001x1x000xxxxxxx110x0x11xxxx", InstName.Vmvn, InstEmit32.Vmvn_II, OpCode32SimdImm.Create, OpCode32SimdImm.CreateT32);
|
||||||
SetA32("<<<<11101x110111xxxx101x01x0xxxx", InstName.Vrintx, InstEmit32.Vrintx_S, OpCode32SimdS.Create);
|
SetAsimd("111100111x11<<01xxxx00111xx0xxxx", InstName.Vneg, InstEmit32.Vneg_V, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32);
|
||||||
SetA32("1111001x1x>>>xxxxxxx0010>xx1xxxx", InstName.Vrshr, InstEmit32.Vrshr, OpCode32SimdShImm.Create);
|
SetAsimd("111100111x111001xxxx01111xx0xxxx", InstName.Vneg, InstEmit32.Vneg_V, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32);
|
||||||
SetA32("111100101x>>>xxxxxxx100001x1xxx0", InstName.Vrshrn, InstEmit32.Vrshrn, OpCode32SimdShImmNarrow.Create);
|
SetAsimd("111100100x11xxxxxxxx0001xxx1xxxx", InstName.Vorn, InstEmit32.Vorn_I, OpCode32SimdBinary.Create, OpCode32SimdBinary.CreateT32);
|
||||||
SetA32("111100111x111011xxxx010x1xx0xxxx", InstName.Vrsqrte, InstEmit32.Vrsqrte, OpCode32SimdSqrte.Create);
|
SetAsimd("111100100x10xxxxxxxx0001xxx1xxxx", InstName.Vorr, InstEmit32.Vorr_I, OpCode32SimdBinary.Create, OpCode32SimdBinary.CreateT32);
|
||||||
SetA32("111100100x10xxxxxxxx1111xxx1xxxx", InstName.Vrsqrts, InstEmit32.Vrsqrts, OpCode32SimdReg.Create);
|
SetAsimd("1111001x1x000xxxxxxx<<x10x01xxxx", InstName.Vorr, InstEmit32.Vorr_II, OpCode32SimdImm.Create, OpCode32SimdImm.CreateT32);
|
||||||
SetA32("1111001x1x>>>xxxxxxx0011>xx1xxxx", InstName.Vrsra, InstEmit32.Vrsra, OpCode32SimdShImm.Create);
|
SetAsimd("111100100x<<xxxxxxxx1011x0x1xxxx", InstName.Vpadd, InstEmit32.Vpadd_I, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("111111100xxxxxxxxxxx101xx0x0xxxx", InstName.Vsel, InstEmit32.Vsel, OpCode32SimdSel.Create);
|
SetAsimd("111100110x00xxxxxxxx1101x0x0xxxx", InstName.Vpadd, InstEmit32.Vpadd_V, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("111100101x>>>xxxxxxx0101>xx1xxxx", InstName.Vshl, InstEmit32.Vshl, OpCode32SimdShImm.Create);
|
SetAsimd("111100111x11<<00xxxx0010xxx0xxxx", InstName.Vpaddl, InstEmit32.Vpaddl, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32);
|
||||||
SetA32("1111001x0xxxxxxxxxxx0100xxx0xxxx", InstName.Vshl, InstEmit32.Vshl_I, OpCode32SimdReg.Create);
|
SetAsimd("1111001x0x<<xxxxxxxx1010x0x0xxxx", InstName.Vpmax, InstEmit32.Vpmax_I, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("1111001x1x>>>xxxxxxx101000x1xxxx", InstName.Vshll, InstEmit32.Vshll, OpCode32SimdShImmLong.Create); // A1 encoding.
|
SetAsimd("111100110x00xxxxxxxx1111x0x0xxxx", InstName.Vpmax, InstEmit32.Vpmax_V, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("1111001x1x>>>xxxxxxx0000>xx1xxxx", InstName.Vshr, InstEmit32.Vshr, OpCode32SimdShImm.Create);
|
SetAsimd("1111001x0x<<xxxxxxxx1010x0x1xxxx", InstName.Vpmin, InstEmit32.Vpmin_I, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("111100101x>>>xxxxxxx100000x1xxx0", InstName.Vshrn, InstEmit32.Vshrn, OpCode32SimdShImmNarrow.Create);
|
SetAsimd("111100110x10xxxxxxxx1111x0x0xxxx", InstName.Vpmin, InstEmit32.Vpmin_V, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("<<<<11101x110001xxxx101x11x0xxxx", InstName.Vsqrt, InstEmit32.Vsqrt_S, OpCode32SimdS.Create);
|
SetAsimd("1111001x0xxxxxxxxxxx0000xxx1xxxx", InstName.Vqadd, InstEmit32.Vqadd, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("1111001x1x>>>xxxxxxx0001>xx1xxxx", InstName.Vsra, InstEmit32.Vsra, OpCode32SimdShImm.Create);
|
SetAsimd("111100100x01xxxxxxxx1011xxx0xxxx", InstName.Vqdmulh, InstEmit32.Vqdmulh, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("111101001x00xxxxxxxx<<00xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemSingle.Create);
|
SetAsimd("111100100x10xxxxxxxx1011xxx0xxxx", InstName.Vqdmulh, InstEmit32.Vqdmulh, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("111101000x00xxxxxxxx0111xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemPair.Create); // Regs = 1.
|
SetAsimd("111100111x11<<10xxxx00101xx0xxx0", InstName.Vqmovn, InstEmit32.Vqmovn, OpCode32SimdMovn.Create, OpCode32SimdMovn.CreateT32);
|
||||||
SetA32("111101000x00xxxxxxxx1010xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemPair.Create); // Regs = 2.
|
SetAsimd("111100111x11<<10xxxx001001x0xxx0", InstName.Vqmovun, InstEmit32.Vqmovun, OpCode32SimdMovn.Create, OpCode32SimdMovn.CreateT32);
|
||||||
SetA32("111101000x00xxxxxxxx0110xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemPair.Create); // Regs = 3.
|
SetAsimd("1111001x1x>>>xxxxxxx100101x1xxx0", InstName.Vqrshrn, InstEmit32.Vqrshrn, OpCode32SimdShImmNarrow.Create, OpCode32SimdShImmNarrow.CreateT32);
|
||||||
SetA32("111101000x00xxxxxxxx0010xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemPair.Create); // Regs = 4.
|
SetAsimd("111100111x>>>xxxxxxx100001x1xxx0", InstName.Vqrshrun, InstEmit32.Vqrshrun, OpCode32SimdShImmNarrow.Create, OpCode32SimdShImmNarrow.CreateT32);
|
||||||
SetA32("111101001x00xxxxxxxx<<01xxxxxxxx", InstName.Vst2, InstEmit32.Vst2, OpCode32SimdMemSingle.Create);
|
SetAsimd("1111001x1x>>>xxxxxxx100100x1xxx0", InstName.Vqshrn, InstEmit32.Vqshrn, OpCode32SimdShImmNarrow.Create, OpCode32SimdShImmNarrow.CreateT32);
|
||||||
SetA32("111101000x00xxxxxxxx100xxxxxxxxx", InstName.Vst2, InstEmit32.Vst2, OpCode32SimdMemPair.Create); // Regs = 1, inc = 1/2 (itype).
|
SetAsimd("111100111x>>>xxxxxxx100000x1xxx0", InstName.Vqshrun, InstEmit32.Vqshrun, OpCode32SimdShImmNarrow.Create, OpCode32SimdShImmNarrow.CreateT32);
|
||||||
SetA32("111101000x00xxxxxxxx0011xxxxxxxx", InstName.Vst2, InstEmit32.Vst2, OpCode32SimdMemPair.Create); // Regs = 2, inc = 2.
|
SetAsimd("1111001x0xxxxxxxxxxx0010xxx1xxxx", InstName.Vqsub, InstEmit32.Vqsub, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("111101001x00xxxxxxxx<<10xxxxxxxx", InstName.Vst3, InstEmit32.Vst3, OpCode32SimdMemSingle.Create);
|
SetAsimd("111100111x111011xxxx010x0xx0xxxx", InstName.Vrecpe, InstEmit32.Vrecpe, OpCode32SimdSqrte.Create, OpCode32SimdSqrte.CreateT32);
|
||||||
SetA32("111101000x00xxxxxxxx010xxxxxxxxx", InstName.Vst3, InstEmit32.Vst3, OpCode32SimdMemPair.Create); // Inc = 1/2 (itype).
|
SetAsimd("111100100x00xxxxxxxx1111xxx1xxxx", InstName.Vrecps, InstEmit32.Vrecps, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("111101001x00xxxxxxxx<<11xxxxxxxx", InstName.Vst4, InstEmit32.Vst4, OpCode32SimdMemSingle.Create);
|
SetAsimd("111100111x11xx00xxxx000<<xx0xxxx", InstName.Vrev, InstEmit32.Vrev, OpCode32SimdRev.Create, OpCode32SimdRev.CreateT32);
|
||||||
SetA32("111101000x00xxxxxxxx000xxxxxxxxx", InstName.Vst4, InstEmit32.Vst4, OpCode32SimdMemPair.Create); // Inc = 1/2 (itype).
|
SetAsimd("1111001x0x<<xxxxxxxx0001xxx0xxxx", InstName.Vrhadd, InstEmit32.Vrhadd, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("<<<<11001x00xxxxxxxx1011xxxxxxx0", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create);
|
SetAsimd("111100111x111010xxxx01010xx0xxxx", InstName.Vrinta, InstEmit32.Vrinta_V, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32);
|
||||||
SetA32("<<<<11001x10xxxxxxxx1011xxxxxxx0", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create);
|
SetAsimd("111100111x111010xxxx01101xx0xxxx", InstName.Vrintm, InstEmit32.Vrintm_V, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32);
|
||||||
SetA32("<<<<11010x10xxxxxxxx1011xxxxxxx0", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create);
|
SetAsimd("111100111x111010xxxx01000xx0xxxx", InstName.Vrintn, InstEmit32.Vrintn_V, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32);
|
||||||
SetA32("<<<<11001x00xxxxxxxx1010xxxxxxxx", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create);
|
SetAsimd("111100111x111010xxxx01111xx0xxxx", InstName.Vrintp, InstEmit32.Vrintp_V, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32);
|
||||||
SetA32("<<<<11001x10xxxxxxxx1010xxxxxxxx", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create);
|
SetAsimd("1111001x1x>>>xxxxxxx0010>xx1xxxx", InstName.Vrshr, InstEmit32.Vrshr, OpCode32SimdShImm.Create, OpCode32SimdShImm.CreateT32);
|
||||||
SetA32("<<<<11010x10xxxxxxxx1010xxxxxxxx", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create);
|
SetAsimd("111100101x>>>xxxxxxx100001x1xxx0", InstName.Vrshrn, InstEmit32.Vrshrn, OpCode32SimdShImmNarrow.Create, OpCode32SimdShImmNarrow.CreateT32);
|
||||||
SetA32("<<<<1101xx00xxxxxxxx101xxxxxxxxx", InstName.Vstr, InstEmit32.Vstr, OpCode32SimdMemImm.Create);
|
SetAsimd("111100111x111011xxxx010x1xx0xxxx", InstName.Vrsqrte, InstEmit32.Vrsqrte, OpCode32SimdSqrte.Create, OpCode32SimdSqrte.CreateT32);
|
||||||
SetA32("111100110xxxxxxxxxxx1000xxx0xxxx", InstName.Vsub, InstEmit32.Vsub_I, OpCode32SimdReg.Create);
|
SetAsimd("111100100x10xxxxxxxx1111xxx1xxxx", InstName.Vrsqrts, InstEmit32.Vrsqrts, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("<<<<11100x11xxxxxxxx101xx1x0xxxx", InstName.Vsub, InstEmit32.Vsub_S, OpCode32SimdRegS.Create);
|
SetAsimd("1111001x1x>>>xxxxxxx0011>xx1xxxx", InstName.Vrsra, InstEmit32.Vrsra, OpCode32SimdShImm.Create, OpCode32SimdShImm.CreateT32);
|
||||||
SetA32("111100100x10xxxxxxxx1101xxx0xxxx", InstName.Vsub, InstEmit32.Vsub_V, OpCode32SimdReg.Create);
|
SetAsimd("111100101x>>>xxxxxxx0101>xx1xxxx", InstName.Vshl, InstEmit32.Vshl, OpCode32SimdShImm.Create, OpCode32SimdShImm.CreateT32);
|
||||||
SetA32("1111001x1x<<xxxxxxx00010x0x0xxxx", InstName.Vsubl, InstEmit32.Vsubl_I, OpCode32SimdRegLong.Create);
|
SetAsimd("1111001x0xxxxxxxxxxx0100xxx0xxxx", InstName.Vshl, InstEmit32.Vshl_I, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetA32("1111001x1x<<xxxxxxx00011x0x0xxxx", InstName.Vsubw, InstEmit32.Vsubw_I, OpCode32SimdRegWide.Create);
|
SetAsimd("1111001x1x>>>xxxxxxx101000x1xxxx", InstName.Vshll, InstEmit32.Vshll, OpCode32SimdShImmLong.Create, OpCode32SimdShImmLong.CreateT32); // A1 encoding.
|
||||||
SetA32("111100111x11xxxxxxxx10xxxxx0xxxx", InstName.Vtbl, InstEmit32.Vtbl, OpCode32SimdTbl.Create);
|
SetAsimd("1111001x1x>>>xxxxxxx0000>xx1xxxx", InstName.Vshr, InstEmit32.Vshr, OpCode32SimdShImm.Create, OpCode32SimdShImm.CreateT32);
|
||||||
SetA32("111100111x11<<10xxxx00001xx0xxxx", InstName.Vtrn, InstEmit32.Vtrn, OpCode32SimdCmpZ.Create);
|
SetAsimd("111100101x>>>xxxxxxx100000x1xxx0", InstName.Vshrn, InstEmit32.Vshrn, OpCode32SimdShImmNarrow.Create, OpCode32SimdShImmNarrow.CreateT32);
|
||||||
SetA32("111100100x<<xxxxxxxx1000xxx1xxxx", InstName.Vtst, InstEmit32.Vtst, OpCode32SimdReg.Create);
|
SetAsimd("1111001x1x>>>xxxxxxx0001>xx1xxxx", InstName.Vsra, InstEmit32.Vsra, OpCode32SimdShImm.Create, OpCode32SimdShImm.CreateT32);
|
||||||
SetA32("111100111x11<<10xxxx00010xx0xxxx", InstName.Vuzp, InstEmit32.Vuzp, OpCode32SimdCmpZ.Create);
|
SetAsimd("111101001x00xxxxxxxx0000xxx0xxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32);
|
||||||
SetA32("111100111x11<<10xxxx00011xx0xxxx", InstName.Vzip, InstEmit32.Vzip, OpCode32SimdCmpZ.Create);
|
SetAsimd("111101001x00xxxxxxxx0100xx0xxxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32);
|
||||||
|
SetAsimd("111101001x00xxxxxxxx1000x000xxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32);
|
||||||
|
SetAsimd("111101001x00xxxxxxxx1000x011xxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32);
|
||||||
|
SetAsimd("111101000x00xxxxxxxx0111xx0xxxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemPair.Create, OpCode32SimdMemPair.CreateT32); // Regs = 1.
|
||||||
|
SetAsimd("111101000x00xxxxxxxx1010xx<<xxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemPair.Create, OpCode32SimdMemPair.CreateT32); // Regs = 2.
|
||||||
|
SetAsimd("111101000x00xxxxxxxx0110xx0xxxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemPair.Create, OpCode32SimdMemPair.CreateT32); // Regs = 3.
|
||||||
|
SetAsimd("111101000x00xxxxxxxx0010xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemPair.Create, OpCode32SimdMemPair.CreateT32); // Regs = 4.
|
||||||
|
SetAsimd("111101001x00xxxxxxxx0x01xxxxxxxx", InstName.Vst2, InstEmit32.Vst2, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32);
|
||||||
|
SetAsimd("111101001x00xxxxxxxx1001xx0xxxxx", InstName.Vst2, InstEmit32.Vst2, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32);
|
||||||
|
SetAsimd("111101000x00xxxxxxxx100x<<0xxxxx", InstName.Vst2, InstEmit32.Vst2, OpCode32SimdMemPair.Create, OpCode32SimdMemPair.CreateT32); // Regs = 1, inc = 1/2 (itype).
|
||||||
|
SetAsimd("111101000x00xxxxxxxx100x<<10xxxx", InstName.Vst2, InstEmit32.Vst2, OpCode32SimdMemPair.Create, OpCode32SimdMemPair.CreateT32); // Regs = 1, inc = 1/2 (itype).
|
||||||
|
SetAsimd("111101000x00xxxxxxxx0011<<xxxxxx", InstName.Vst2, InstEmit32.Vst2, OpCode32SimdMemPair.Create, OpCode32SimdMemPair.CreateT32); // Regs = 2, inc = 2.
|
||||||
|
SetAsimd("111101001x00xxxxxxxx0x10xxx0xxxx", InstName.Vst3, InstEmit32.Vst3, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32);
|
||||||
|
SetAsimd("111101001x00xxxxxxxx1010xx00xxxx", InstName.Vst3, InstEmit32.Vst3, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32);
|
||||||
|
SetAsimd("111101000x00xxxxxxxx010x<<0xxxxx", InstName.Vst3, InstEmit32.Vst3, OpCode32SimdMemPair.Create, OpCode32SimdMemPair.CreateT32); // Inc = 1/2 (itype).
|
||||||
|
SetAsimd("111101001x00xxxxxxxx0x11xxxxxxxx", InstName.Vst4, InstEmit32.Vst4, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32);
|
||||||
|
SetAsimd("111101001x00xxxxxxxx1011xx<<xxxx", InstName.Vst4, InstEmit32.Vst4, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32);
|
||||||
|
SetAsimd("111101000x00xxxxxxxx000x<<xxxxxx", InstName.Vst4, InstEmit32.Vst4, OpCode32SimdMemPair.Create, OpCode32SimdMemPair.CreateT32); // Inc = 1/2 (itype).
|
||||||
|
SetAsimd("111100110xxxxxxxxxxx1000xxx0xxxx", InstName.Vsub, InstEmit32.Vsub_I, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
|
SetAsimd("111100100x10xxxxxxxx1101xxx0xxxx", InstName.Vsub, InstEmit32.Vsub_V, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
|
SetAsimd("1111001x1x<<xxxxxxx00010x0x0xxxx", InstName.Vsubl, InstEmit32.Vsubl_I, OpCode32SimdRegLong.Create, OpCode32SimdRegLong.CreateT32);
|
||||||
|
SetAsimd("1111001x1x<<xxxxxxx00011x0x0xxxx", InstName.Vsubw, InstEmit32.Vsubw_I, OpCode32SimdRegWide.Create, OpCode32SimdRegWide.CreateT32);
|
||||||
|
SetAsimd("111100111x11xxxxxxxx10xxxxx0xxxx", InstName.Vtbl, InstEmit32.Vtbl, OpCode32SimdTbl.Create, OpCode32SimdTbl.CreateT32);
|
||||||
|
SetAsimd("111100111x11<<10xxxx00001xx0xxxx", InstName.Vtrn, InstEmit32.Vtrn, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32);
|
||||||
|
SetAsimd("111100100x<<xxxxxxxx1000xxx1xxxx", InstName.Vtst, InstEmit32.Vtst, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
|
SetAsimd("111100111x11<<10xxxx00010xx0xxxx", InstName.Vuzp, InstEmit32.Vuzp, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32);
|
||||||
|
SetAsimd("111100111x11<<10xxxx00011xx0xxxx", InstName.Vzip, InstEmit32.Vzip, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "OpCode Table (AArch32, T16)"
|
#region "OpCode Table (AArch32, T16)"
|
||||||
@@ -1054,7 +1107,14 @@ namespace ARMeilleure.Decoders
|
|||||||
SetT16("1011101011xxxxxx", InstName.Revsh, InstEmit32.Revsh, OpCodeT16AluRegLow.Create);
|
SetT16("1011101011xxxxxx", InstName.Revsh, InstEmit32.Revsh, OpCodeT16AluRegLow.Create);
|
||||||
SetT16("101110x1xxxxxxxx", InstName.Cbnz, InstEmit32.Cbnz, OpCodeT16BImmCmp.Create);
|
SetT16("101110x1xxxxxxxx", InstName.Cbnz, InstEmit32.Cbnz, OpCodeT16BImmCmp.Create);
|
||||||
SetT16("1011110xxxxxxxxx", InstName.Pop, InstEmit32.Ldm, OpCodeT16MemStack.Create);
|
SetT16("1011110xxxxxxxxx", InstName.Pop, InstEmit32.Ldm, OpCodeT16MemStack.Create);
|
||||||
SetT16("10111111xxxx0000", InstName.Nop, InstEmit32.Nop, OpCodeT16.Create);
|
SetT16("1011111100000000", InstName.Nop, InstEmit32.Nop, OpCodeT16.Create);
|
||||||
|
SetT16("1011111100010000", InstName.Yield, InstEmit32.Nop, OpCodeT16.Create);
|
||||||
|
SetT16("1011111100100000", InstName.Wfe, InstEmit32.Nop, OpCodeT16.Create);
|
||||||
|
SetT16("1011111100110000", InstName.Wfi, InstEmit32.Nop, OpCodeT16.Create);
|
||||||
|
SetT16("1011111101000000", InstName.Sev, InstEmit32.Nop, OpCodeT16.Create);
|
||||||
|
SetT16("1011111101010000", InstName.Sevl, InstEmit32.Nop, OpCodeT16.Create);
|
||||||
|
SetT16("10111111011x0000", InstName.Hint, InstEmit32.Nop, OpCodeT16.Create); // Hint instruction
|
||||||
|
SetT16("101111111xxx0000", InstName.Hint, InstEmit32.Nop, OpCodeT16.Create); // Hint instruction
|
||||||
SetT16("10111111xxxx>>>>", InstName.It, InstEmit32.It, OpCodeT16IfThen.Create);
|
SetT16("10111111xxxx>>>>", InstName.It, InstEmit32.It, OpCodeT16IfThen.Create);
|
||||||
SetT16("11000xxxxxxxxxxx", InstName.Stm, InstEmit32.Stm, OpCodeT16MemMult.Create);
|
SetT16("11000xxxxxxxxxxx", InstName.Stm, InstEmit32.Stm, OpCodeT16MemMult.Create);
|
||||||
SetT16("11001xxxxxxxxxxx", InstName.Ldm, InstEmit32.Ldm, OpCodeT16MemMult.Create);
|
SetT16("11001xxxxxxxxxxx", InstName.Ldm, InstEmit32.Ldm, OpCodeT16MemMult.Create);
|
||||||
@@ -1074,6 +1134,8 @@ namespace ARMeilleure.Decoders
|
|||||||
SetT32("11110x00000<xxxx0xxx<<<<xxxxxxxx", InstName.And, InstEmit32.And, OpCodeT32AluImm.Create);
|
SetT32("11110x00000<xxxx0xxx<<<<xxxxxxxx", InstName.And, InstEmit32.And, OpCodeT32AluImm.Create);
|
||||||
SetT32("11110x<<<xxxxxxx10x0xxxxxxxxxxxx", InstName.B, InstEmit32.B, OpCodeT32BImm20.Create);
|
SetT32("11110x<<<xxxxxxx10x0xxxxxxxxxxxx", InstName.B, InstEmit32.B, OpCodeT32BImm20.Create);
|
||||||
SetT32("11110xxxxxxxxxxx10x1xxxxxxxxxxxx", InstName.B, InstEmit32.B, OpCodeT32BImm24.Create);
|
SetT32("11110xxxxxxxxxxx10x1xxxxxxxxxxxx", InstName.B, InstEmit32.B, OpCodeT32BImm24.Create);
|
||||||
|
SetT32("11110011011011110xxxxxxxxx0xxxxx", InstName.Bfc, InstEmit32.Bfc, OpCodeT32AluBf.Create);
|
||||||
|
SetT32("111100110110<<<<0xxxxxxxxx0xxxxx", InstName.Bfi, InstEmit32.Bfi, OpCodeT32AluBf.Create);
|
||||||
SetT32("11101010001xxxxx0xxxxxxxxxxxxxxx", InstName.Bic, InstEmit32.Bic, OpCodeT32AluRsImm.Create);
|
SetT32("11101010001xxxxx0xxxxxxxxxxxxxxx", InstName.Bic, InstEmit32.Bic, OpCodeT32AluRsImm.Create);
|
||||||
SetT32("11110x00001xxxxx0xxxxxxxxxxxxxxx", InstName.Bic, InstEmit32.Bic, OpCodeT32AluImm.Create);
|
SetT32("11110x00001xxxxx0xxxxxxxxxxxxxxx", InstName.Bic, InstEmit32.Bic, OpCodeT32AluImm.Create);
|
||||||
SetT32("11110xxxxxxxxxxx11x1xxxxxxxxxxxx", InstName.Bl, InstEmit32.Bl, OpCodeT32BImm24.Create);
|
SetT32("11110xxxxxxxxxxx11x1xxxxxxxxxxxx", InstName.Bl, InstEmit32.Bl, OpCodeT32BImm24.Create);
|
||||||
@@ -1083,39 +1145,64 @@ namespace ARMeilleure.Decoders
|
|||||||
SetT32("11110x010001xxxx0xxx1111xxxxxxxx", InstName.Cmn, InstEmit32.Cmn, OpCodeT32AluImm.Create);
|
SetT32("11110x010001xxxx0xxx1111xxxxxxxx", InstName.Cmn, InstEmit32.Cmn, OpCodeT32AluImm.Create);
|
||||||
SetT32("111010111011xxxx0xxx1111xxxxxxxx", InstName.Cmp, InstEmit32.Cmp, OpCodeT32AluRsImm.Create);
|
SetT32("111010111011xxxx0xxx1111xxxxxxxx", InstName.Cmp, InstEmit32.Cmp, OpCodeT32AluRsImm.Create);
|
||||||
SetT32("11110x011011xxxx0xxx1111xxxxxxxx", InstName.Cmp, InstEmit32.Cmp, OpCodeT32AluImm.Create);
|
SetT32("11110x011011xxxx0xxx1111xxxxxxxx", InstName.Cmp, InstEmit32.Cmp, OpCodeT32AluImm.Create);
|
||||||
|
SetT32("11110011101011111000000000010100", InstName.Csdb, InstEmit32.Csdb, OpCodeT32.Create);
|
||||||
SetT32("11101010100<xxxx0xxx<<<<xxxxxxxx", InstName.Eor, InstEmit32.Eor, OpCodeT32AluRsImm.Create);
|
SetT32("11101010100<xxxx0xxx<<<<xxxxxxxx", InstName.Eor, InstEmit32.Eor, OpCodeT32AluRsImm.Create);
|
||||||
SetT32("11110x00100<xxxx0xxx<<<<xxxxxxxx", InstName.Eor, InstEmit32.Eor, OpCodeT32AluImm.Create);
|
SetT32("11110x00100<xxxx0xxx<<<<xxxxxxxx", InstName.Eor, InstEmit32.Eor, OpCodeT32AluImm.Create);
|
||||||
|
SetT32("11110011101011111000000000010000", InstName.Esb, InstEmit32.Nop, OpCodeT32.Create); // Error Synchronization Barrier (FEAT_RAS)
|
||||||
|
SetT32("1111001110101111100000000000011x", InstName.Hint, InstEmit32.Nop, OpCodeT32.Create); // Reserved Hint
|
||||||
|
SetT32("11110011101011111000000000001xxx", InstName.Hint, InstEmit32.Nop, OpCodeT32.Create); // Reserved Hint
|
||||||
|
SetT32("11110011101011111000000000010001", InstName.Hint, InstEmit32.Nop, OpCodeT32.Create); // Reserved Hint
|
||||||
|
SetT32("11110011101011111000000000010011", InstName.Hint, InstEmit32.Nop, OpCodeT32.Create); // Reserved Hint
|
||||||
|
SetT32("11110011101011111000000000010101", InstName.Hint, InstEmit32.Nop, OpCodeT32.Create); // Reserved Hint
|
||||||
|
SetT32("1111001110101111100000000001011x", InstName.Hint, InstEmit32.Nop, OpCodeT32.Create); // Reserved Hint
|
||||||
|
SetT32("11110011101011111000000000011xxx", InstName.Hint, InstEmit32.Nop, OpCodeT32.Create); // Reserved Hint
|
||||||
|
SetT32("111100111010111110000000001xxxxx", InstName.Hint, InstEmit32.Nop, OpCodeT32.Create); // Reserved Hint
|
||||||
|
SetT32("11110011101011111000000001xxxxxx", InstName.Hint, InstEmit32.Nop, OpCodeT32.Create); // Reserved Hint
|
||||||
|
SetT32("1111001110101111100000001xxxxxxx", InstName.Hint, InstEmit32.Nop, OpCodeT32.Create); // Reserved Hint
|
||||||
SetT32("111010001101xxxxxxxx111110101111", InstName.Lda, InstEmit32.Lda, OpCodeT32MemLdEx.Create);
|
SetT32("111010001101xxxxxxxx111110101111", InstName.Lda, InstEmit32.Lda, OpCodeT32MemLdEx.Create);
|
||||||
|
SetT32("111010001101xxxxxxxx111110001111", InstName.Ldab, InstEmit32.Ldab, OpCodeT32MemLdEx.Create);
|
||||||
SetT32("111010001101xxxxxxxx111111101111", InstName.Ldaex, InstEmit32.Ldaex, OpCodeT32MemLdEx.Create);
|
SetT32("111010001101xxxxxxxx111111101111", InstName.Ldaex, InstEmit32.Ldaex, OpCodeT32MemLdEx.Create);
|
||||||
|
SetT32("111010001101xxxxxxxx111111001111", InstName.Ldaexb, InstEmit32.Ldaexb, OpCodeT32MemLdEx.Create);
|
||||||
|
SetT32("111010001101xxxxxxxxxxxx11111111", InstName.Ldaexd, InstEmit32.Ldaexd, OpCodeT32MemLdEx.Create);
|
||||||
|
SetT32("111010001101xxxxxxxx111111011111", InstName.Ldaexh, InstEmit32.Ldaexh, OpCodeT32MemLdEx.Create);
|
||||||
|
SetT32("111010001101xxxxxxxx111110011111", InstName.Ldah, InstEmit32.Ldah, OpCodeT32MemLdEx.Create);
|
||||||
SetT32("1110100010x1xxxxxxxxxxxxxxxxxxxx", InstName.Ldm, InstEmit32.Ldm, OpCodeT32MemMult.Create);
|
SetT32("1110100010x1xxxxxxxxxxxxxxxxxxxx", InstName.Ldm, InstEmit32.Ldm, OpCodeT32MemMult.Create);
|
||||||
SetT32("1110100100x1xxxxxxxxxxxxxxxxxxxx", InstName.Ldm, InstEmit32.Ldm, OpCodeT32MemMult.Create);
|
SetT32("1110100100x1xxxxxxxxxxxxxxxxxxxx", InstName.Ldm, InstEmit32.Ldm, OpCodeT32MemMult.Create);
|
||||||
SetT32("111110000101xxxx<<<<10x1xxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT32MemImm8.Create);
|
SetT32("111110000101xxxxxxxx10x1xxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT32MemImm8.Create);
|
||||||
SetT32("111110000101xxxx<<<<1100xxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT32MemImm8.Create);
|
SetT32("111110000101xxxxxxxx1100xxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT32MemImm8.Create);
|
||||||
SetT32("111110000101xxxx<<<<11x1xxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT32MemImm8.Create);
|
SetT32("111110000101xxxxxxxx11x1xxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT32MemImm8.Create);
|
||||||
SetT32("111110001101xxxxxxxxxxxxxxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT32MemImm12.Create);
|
SetT32("111110001101xxxxxxxxxxxxxxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT32MemImm12.Create);
|
||||||
SetT32("111110000101<<<<xxxx000000xxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT32MemRsImm.Create);
|
SetT32("111110000101<<<<xxxx000000xxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT32MemRsImm.Create);
|
||||||
SetT32("111110000001xxxx<<<<10x1xxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT32MemImm8.Create);
|
SetT32("111110000001xxxxxxxx10x1xxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT32MemImm8.Create);
|
||||||
SetT32("111110000001xxxx<<<<1100xxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT32MemImm8.Create);
|
SetT32("111110000001xxxx<<<<1100xxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT32MemImm8.Create);
|
||||||
SetT32("111110000001xxxx<<<<11x1xxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT32MemImm8.Create);
|
SetT32("111110000001xxxxxxxx11x1xxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT32MemImm8.Create);
|
||||||
SetT32("111110001001xxxxxxxxxxxxxxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT32MemImm12.Create);
|
SetT32("111110001001xxxx<<<<xxxxxxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT32MemImm12.Create);
|
||||||
|
SetT32("111110000001xxxx<<<<000000xxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT32MemRsImm.Create);
|
||||||
SetT32("11101000x111<<<<xxxxxxxxxxxxxxxx", InstName.Ldrd, InstEmit32.Ldrd, OpCodeT32MemImm8D.Create);
|
SetT32("11101000x111<<<<xxxxxxxxxxxxxxxx", InstName.Ldrd, InstEmit32.Ldrd, OpCodeT32MemImm8D.Create);
|
||||||
SetT32("11101001x1x1<<<<xxxxxxxxxxxxxxxx", InstName.Ldrd, InstEmit32.Ldrd, OpCodeT32MemImm8D.Create);
|
SetT32("11101001x1x1<<<<xxxxxxxxxxxxxxxx", InstName.Ldrd, InstEmit32.Ldrd, OpCodeT32MemImm8D.Create);
|
||||||
SetT32("111110000011xxxx<<<<10x1xxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT32MemImm8.Create);
|
SetT32("111110000011xxxxxxxx10x1xxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT32MemImm8.Create);
|
||||||
SetT32("111110000011xxxx<<<<1100xxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT32MemImm8.Create);
|
SetT32("111110000011xxxx<<<<1100xxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT32MemImm8.Create);
|
||||||
SetT32("111110000011xxxx<<<<11x1xxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT32MemImm8.Create);
|
SetT32("111110000011xxxxxxxx11x1xxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT32MemImm8.Create);
|
||||||
SetT32("111110001011xxxxxxxxxxxxxxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT32MemImm12.Create);
|
SetT32("111110001011xxxx<<<<xxxxxxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT32MemImm12.Create);
|
||||||
SetT32("111110010001xxxx<<<<10x1xxxxxxxx", InstName.Ldrsb, InstEmit32.Ldrsb, OpCodeT32MemImm8.Create);
|
SetT32("111110000011xxxx<<<<000000xxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT32MemRsImm.Create);
|
||||||
|
SetT32("111110010001xxxxxxxx10x1xxxxxxxx", InstName.Ldrsb, InstEmit32.Ldrsb, OpCodeT32MemImm8.Create);
|
||||||
SetT32("111110010001xxxx<<<<1100xxxxxxxx", InstName.Ldrsb, InstEmit32.Ldrsb, OpCodeT32MemImm8.Create);
|
SetT32("111110010001xxxx<<<<1100xxxxxxxx", InstName.Ldrsb, InstEmit32.Ldrsb, OpCodeT32MemImm8.Create);
|
||||||
SetT32("111110010001xxxx<<<<11x1xxxxxxxx", InstName.Ldrsb, InstEmit32.Ldrsb, OpCodeT32MemImm8.Create);
|
SetT32("111110010001xxxxxxxx11x1xxxxxxxx", InstName.Ldrsb, InstEmit32.Ldrsb, OpCodeT32MemImm8.Create);
|
||||||
SetT32("111110011001xxxxxxxxxxxxxxxxxxxx", InstName.Ldrsb, InstEmit32.Ldrsb, OpCodeT32MemImm12.Create);
|
SetT32("111110011001xxxx<<<<xxxxxxxxxxxx", InstName.Ldrsb, InstEmit32.Ldrsb, OpCodeT32MemImm12.Create);
|
||||||
SetT32("111110010011xxxx<<<<10x1xxxxxxxx", InstName.Ldrsh, InstEmit32.Ldrsh, OpCodeT32MemImm8.Create);
|
SetT32("111110010001xxxx<<<<000000xxxxxx", InstName.Ldrsb, InstEmit32.Ldrsb, OpCodeT32MemRsImm.Create);
|
||||||
|
SetT32("111110010011xxxxxxxx10x1xxxxxxxx", InstName.Ldrsh, InstEmit32.Ldrsh, OpCodeT32MemImm8.Create);
|
||||||
SetT32("111110010011xxxx<<<<1100xxxxxxxx", InstName.Ldrsh, InstEmit32.Ldrsh, OpCodeT32MemImm8.Create);
|
SetT32("111110010011xxxx<<<<1100xxxxxxxx", InstName.Ldrsh, InstEmit32.Ldrsh, OpCodeT32MemImm8.Create);
|
||||||
SetT32("111110010011xxxx<<<<11x1xxxxxxxx", InstName.Ldrsh, InstEmit32.Ldrsh, OpCodeT32MemImm8.Create);
|
SetT32("111110010011xxxxxxxx11x1xxxxxxxx", InstName.Ldrsh, InstEmit32.Ldrsh, OpCodeT32MemImm8.Create);
|
||||||
SetT32("111110011011xxxxxxxxxxxxxxxxxxxx", InstName.Ldrsh, InstEmit32.Ldrsh, OpCodeT32MemImm12.Create);
|
SetT32("111110011011xxxx<<<<xxxxxxxxxxxx", InstName.Ldrsh, InstEmit32.Ldrsh, OpCodeT32MemImm12.Create);
|
||||||
|
SetT32("111110010011xxxx<<<<000000xxxxxx", InstName.Ldrsh, InstEmit32.Ldrsh, OpCodeT32MemRsImm.Create);
|
||||||
|
SetT32("111110110000xxxx<<<<xxxx0000xxxx", InstName.Mla, InstEmit32.Mla, OpCodeT32AluMla.Create);
|
||||||
|
SetT32("111110110000xxxxxxxxxxxx0001xxxx", InstName.Mls, InstEmit32.Mls, OpCodeT32AluMla.Create);
|
||||||
SetT32("11101010010x11110xxxxxxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT32AluRsImm.Create);
|
SetT32("11101010010x11110xxxxxxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT32AluRsImm.Create);
|
||||||
SetT32("111110100xxxxxxx1111xxxx0000xxxx", InstName.Mov, InstEmit32.Mov, OpCodeT32ShiftReg.Create);
|
SetT32("111110100xxxxxxx1111xxxx0000xxxx", InstName.Mov, InstEmit32.Mov, OpCodeT32ShiftReg.Create);
|
||||||
SetT32("11110x00010x11110xxxxxxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT32AluImm.Create);
|
SetT32("11110x00010x11110xxxxxxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT32AluImm.Create);
|
||||||
SetT32("11110x100100xxxx0xxxxxxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT32MovImm16.Create);
|
SetT32("11110x100100xxxx0xxxxxxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT32MovImm16.Create);
|
||||||
|
SetT32("11110x101100xxxx0xxxxxxxxxxxxxxx", InstName.Movt, InstEmit32.Movt, OpCodeT32MovImm16.Create);
|
||||||
|
SetT32("111110110000xxxx1111xxxx0000xxxx", InstName.Mul, InstEmit32.Mul, OpCodeT32AluMla.Create);
|
||||||
SetT32("11101010011x11110xxxxxxxxxxxxxxx", InstName.Mvn, InstEmit32.Mvn, OpCodeT32AluRsImm.Create);
|
SetT32("11101010011x11110xxxxxxxxxxxxxxx", InstName.Mvn, InstEmit32.Mvn, OpCodeT32AluRsImm.Create);
|
||||||
SetT32("11110x00011x11110xxxxxxxxxxxxxxx", InstName.Mvn, InstEmit32.Mvn, OpCodeT32AluImm.Create);
|
SetT32("11110x00011x11110xxxxxxxxxxxxxxx", InstName.Mvn, InstEmit32.Mvn, OpCodeT32AluImm.Create);
|
||||||
SetT32("11110011101011111000000000000000", InstName.Nop, InstEmit32.Nop, OpCodeT32.Create);
|
SetT32("11110011101011111000000000000000", InstName.Nop, InstEmit32.Nop, OpCodeT32.Create);
|
||||||
@@ -1123,30 +1210,85 @@ namespace ARMeilleure.Decoders
|
|||||||
SetT32("11110x00011x<<<<0xxxxxxxxxxxxxxx", InstName.Orn, InstEmit32.Orn, OpCodeT32AluImm.Create);
|
SetT32("11110x00011x<<<<0xxxxxxxxxxxxxxx", InstName.Orn, InstEmit32.Orn, OpCodeT32AluImm.Create);
|
||||||
SetT32("11101010010x<<<<0xxxxxxxxxxxxxxx", InstName.Orr, InstEmit32.Orr, OpCodeT32AluRsImm.Create);
|
SetT32("11101010010x<<<<0xxxxxxxxxxxxxxx", InstName.Orr, InstEmit32.Orr, OpCodeT32AluRsImm.Create);
|
||||||
SetT32("11110x00010x<<<<0xxxxxxxxxxxxxxx", InstName.Orr, InstEmit32.Orr, OpCodeT32AluImm.Create);
|
SetT32("11110x00010x<<<<0xxxxxxxxxxxxxxx", InstName.Orr, InstEmit32.Orr, OpCodeT32AluImm.Create);
|
||||||
|
SetT32("1111100010x1xxxx1111xxxxxxxxxxxx", InstName.Pld, InstEmit32.Nop, OpCodeT32.Create);
|
||||||
|
SetT32("1111100000x1xxxx11111100xxxxxxxx", InstName.Pld, InstEmit32.Nop, OpCodeT32.Create);
|
||||||
|
SetT32("1111100000x1xxxx1111000000xxxxxx", InstName.Pld, InstEmit32.Nop, OpCodeT32.Create);
|
||||||
SetT32("11101011110xxxxx0xxxxxxxxxxxxxxx", InstName.Rsb, InstEmit32.Rsb, OpCodeT32AluRsImm.Create);
|
SetT32("11101011110xxxxx0xxxxxxxxxxxxxxx", InstName.Rsb, InstEmit32.Rsb, OpCodeT32AluRsImm.Create);
|
||||||
SetT32("11110x01110xxxxx0xxxxxxxxxxxxxxx", InstName.Rsb, InstEmit32.Rsb, OpCodeT32AluImm.Create);
|
SetT32("11110x01110xxxxx0xxxxxxxxxxxxxxx", InstName.Rsb, InstEmit32.Rsb, OpCodeT32AluImm.Create);
|
||||||
|
SetT32("111110101000xxxx1111xxxx0000xxxx", InstName.Sadd8, InstEmit32.Sadd8, OpCodeT32AluReg.Create);
|
||||||
SetT32("11101011011xxxxx0xxxxxxxxxxxxxxx", InstName.Sbc, InstEmit32.Sbc, OpCodeT32AluRsImm.Create);
|
SetT32("11101011011xxxxx0xxxxxxxxxxxxxxx", InstName.Sbc, InstEmit32.Sbc, OpCodeT32AluRsImm.Create);
|
||||||
SetT32("11110x01011xxxxx0xxxxxxxxxxxxxxx", InstName.Sbc, InstEmit32.Sbc, OpCodeT32AluImm.Create);
|
SetT32("11110x01011xxxxx0xxxxxxxxxxxxxxx", InstName.Sbc, InstEmit32.Sbc, OpCodeT32AluImm.Create);
|
||||||
|
SetT32("111100110100xxxx0xxxxxxxxx0xxxxx", InstName.Sbfx, InstEmit32.Sbfx, OpCodeT32AluBf.Create);
|
||||||
|
SetT32("111110111001xxxx1111xxxx1111xxxx", InstName.Sdiv, InstEmit32.Sdiv, OpCodeT32AluMla.Create);
|
||||||
|
SetT32("111110101010xxxx1111xxxx1000xxxx", InstName.Sel, InstEmit32.Sel, OpCodeT32AluReg.Create);
|
||||||
|
SetT32("111110101000xxxx1111xxxx0010xxxx", InstName.Shadd8, InstEmit32.Shadd8, OpCodeT32AluReg.Create);
|
||||||
|
SetT32("111110101100xxxx1111xxxx0010xxxx", InstName.Shsub8, InstEmit32.Shsub8, OpCodeT32AluReg.Create);
|
||||||
|
SetT32("11110011101011111000000000000100", InstName.Sev, InstEmit32.Nop, OpCodeT32.Create);
|
||||||
|
SetT32("11110011101011111000000000000101", InstName.Sevl, InstEmit32.Nop, OpCodeT32.Create);
|
||||||
|
SetT32("111110110001xxxx<<<<xxxx00xxxxxx", InstName.Smla__, InstEmit32.Smla__, OpCodeT32AluMla.Create);
|
||||||
|
SetT32("111110111100xxxxxxxxxxxx0000xxxx", InstName.Smlal, InstEmit32.Smlal, OpCodeT32AluUmull.Create);
|
||||||
|
SetT32("111110111100xxxxxxxxxxxx10xxxxxx", InstName.Smlal__, InstEmit32.Smlal__, OpCodeT32AluUmull.Create);
|
||||||
|
SetT32("111110110011xxxx<<<<xxxx000xxxxx", InstName.Smlaw_, InstEmit32.Smlaw_, OpCodeT32AluMla.Create);
|
||||||
|
SetT32("111110110101xxxx<<<<xxxx000xxxxx", InstName.Smmla, InstEmit32.Smmla, OpCodeT32AluMla.Create);
|
||||||
|
SetT32("111110110110xxxxxxxxxxxx000xxxxx", InstName.Smmls, InstEmit32.Smmls, OpCodeT32AluMla.Create);
|
||||||
|
SetT32("111110110001xxxx1111xxxx00xxxxxx", InstName.Smul__, InstEmit32.Smul__, OpCodeT32AluMla.Create);
|
||||||
|
SetT32("111110111000xxxxxxxxxxxx0000xxxx", InstName.Smull, InstEmit32.Smull, OpCodeT32AluUmull.Create);
|
||||||
|
SetT32("111110110011xxxx1111xxxx000xxxxx", InstName.Smulw_, InstEmit32.Smulw_, OpCodeT32AluMla.Create);
|
||||||
|
SetT32("111110101100xxxx1111xxxx0000xxxx", InstName.Ssub8, InstEmit32.Ssub8, OpCodeT32AluReg.Create);
|
||||||
|
SetT32("111010001100xxxxxxxx111110101111", InstName.Stl, InstEmit32.Stl, OpCodeT32MemStEx.Create);
|
||||||
|
SetT32("111010001100xxxxxxxx111110001111", InstName.Stlb, InstEmit32.Stlb, OpCodeT32MemStEx.Create);
|
||||||
SetT32("111010001100xxxxxxxx11111110xxxx", InstName.Stlex, InstEmit32.Stlex, OpCodeT32MemStEx.Create);
|
SetT32("111010001100xxxxxxxx11111110xxxx", InstName.Stlex, InstEmit32.Stlex, OpCodeT32MemStEx.Create);
|
||||||
|
SetT32("111010001100xxxxxxxx11111100xxxx", InstName.Stlexb, InstEmit32.Stlexb, OpCodeT32MemStEx.Create);
|
||||||
|
SetT32("111010001100xxxxxxxxxxxx1111xxxx", InstName.Stlexd, InstEmit32.Stlexd, OpCodeT32MemStEx.Create);
|
||||||
|
SetT32("111010001100xxxxxxxx11111101xxxx", InstName.Stlexh, InstEmit32.Stlexh, OpCodeT32MemStEx.Create);
|
||||||
|
SetT32("111010001100xxxxxxxx111110011111", InstName.Stlh, InstEmit32.Stlh, OpCodeT32MemStEx.Create);
|
||||||
SetT32("1110100010x0xxxx0xxxxxxxxxxxxxxx", InstName.Stm, InstEmit32.Stm, OpCodeT32MemMult.Create);
|
SetT32("1110100010x0xxxx0xxxxxxxxxxxxxxx", InstName.Stm, InstEmit32.Stm, OpCodeT32MemMult.Create);
|
||||||
SetT32("1110100100x0xxxx0xxxxxxxxxxxxxxx", InstName.Stm, InstEmit32.Stm, OpCodeT32MemMult.Create);
|
SetT32("1110100100x0xxxx0xxxxxxxxxxxxxxx", InstName.Stm, InstEmit32.Stm, OpCodeT32MemMult.Create);
|
||||||
SetT32("111110000100xxxxxxxx1<<>xxxxxxxx", InstName.Str, InstEmit32.Str, OpCodeT32MemImm8.Create);
|
SetT32("111110000100<<<<xxxx10x1xxxxxxxx", InstName.Str, InstEmit32.Str, OpCodeT32MemImm8.Create);
|
||||||
SetT32("111110001100xxxxxxxxxxxxxxxxxxxx", InstName.Str, InstEmit32.Str, OpCodeT32MemImm12.Create);
|
SetT32("111110000100<<<<xxxx1100xxxxxxxx", InstName.Str, InstEmit32.Str, OpCodeT32MemImm8.Create);
|
||||||
|
SetT32("111110000100<<<<xxxx11x1xxxxxxxx", InstName.Str, InstEmit32.Str, OpCodeT32MemImm8.Create);
|
||||||
|
SetT32("111110001100<<<<xxxxxxxxxxxxxxxx", InstName.Str, InstEmit32.Str, OpCodeT32MemImm12.Create);
|
||||||
SetT32("111110000100<<<<xxxx000000xxxxxx", InstName.Str, InstEmit32.Str, OpCodeT32MemRsImm.Create);
|
SetT32("111110000100<<<<xxxx000000xxxxxx", InstName.Str, InstEmit32.Str, OpCodeT32MemRsImm.Create);
|
||||||
SetT32("111110000000xxxxxxxx1<<>xxxxxxxx", InstName.Strb, InstEmit32.Strb, OpCodeT32MemImm8.Create);
|
SetT32("111110000000<<<<xxxx10x1xxxxxxxx", InstName.Strb, InstEmit32.Strb, OpCodeT32MemImm8.Create);
|
||||||
SetT32("111110001000xxxxxxxxxxxxxxxxxxxx", InstName.Strb, InstEmit32.Strb, OpCodeT32MemImm12.Create);
|
SetT32("111110000000<<<<xxxx1100xxxxxxxx", InstName.Strb, InstEmit32.Strb, OpCodeT32MemImm8.Create);
|
||||||
|
SetT32("111110000000<<<<xxxx11x1xxxxxxxx", InstName.Strb, InstEmit32.Strb, OpCodeT32MemImm8.Create);
|
||||||
|
SetT32("111110001000<<<<xxxxxxxxxxxxxxxx", InstName.Strb, InstEmit32.Strb, OpCodeT32MemImm12.Create);
|
||||||
|
SetT32("111110000000<<<<xxxx000000xxxxxx", InstName.Strb, InstEmit32.Strb, OpCodeT32MemRsImm.Create);
|
||||||
SetT32("11101000x110<<<<xxxxxxxxxxxxxxxx", InstName.Strd, InstEmit32.Strd, OpCodeT32MemImm8D.Create);
|
SetT32("11101000x110<<<<xxxxxxxxxxxxxxxx", InstName.Strd, InstEmit32.Strd, OpCodeT32MemImm8D.Create);
|
||||||
SetT32("11101001x1x0<<<<xxxxxxxxxxxxxxxx", InstName.Strd, InstEmit32.Strd, OpCodeT32MemImm8D.Create);
|
SetT32("11101001x1x0<<<<xxxxxxxxxxxxxxxx", InstName.Strd, InstEmit32.Strd, OpCodeT32MemImm8D.Create);
|
||||||
SetT32("111110000010xxxxxxxx1<<>xxxxxxxx", InstName.Strh, InstEmit32.Strh, OpCodeT32MemImm8.Create);
|
SetT32("111110000010<<<<xxxx10x1xxxxxxxx", InstName.Strh, InstEmit32.Strh, OpCodeT32MemImm8.Create);
|
||||||
SetT32("111110001010xxxxxxxxxxxxxxxxxxxx", InstName.Strh, InstEmit32.Strh, OpCodeT32MemImm12.Create);
|
SetT32("111110000010<<<<xxxx1100xxxxxxxx", InstName.Strh, InstEmit32.Strh, OpCodeT32MemImm8.Create);
|
||||||
|
SetT32("111110000010<<<<xxxx11x1xxxxxxxx", InstName.Strh, InstEmit32.Strh, OpCodeT32MemImm8.Create);
|
||||||
|
SetT32("111110001010<<<<xxxxxxxxxxxxxxxx", InstName.Strh, InstEmit32.Strh, OpCodeT32MemImm12.Create);
|
||||||
|
SetT32("111110000010<<<<xxxx000000xxxxxx", InstName.Strh, InstEmit32.Strh, OpCodeT32MemRsImm.Create);
|
||||||
SetT32("11101011101<xxxx0xxx<<<<xxxxxxxx", InstName.Sub, InstEmit32.Sub, OpCodeT32AluRsImm.Create);
|
SetT32("11101011101<xxxx0xxx<<<<xxxxxxxx", InstName.Sub, InstEmit32.Sub, OpCodeT32AluRsImm.Create);
|
||||||
SetT32("11110x01101<xxxx0xxx<<<<xxxxxxxx", InstName.Sub, InstEmit32.Sub, OpCodeT32AluImm.Create);
|
SetT32("11110x01101<xxxx0xxx<<<<xxxxxxxx", InstName.Sub, InstEmit32.Sub, OpCodeT32AluImm.Create);
|
||||||
|
SetT32("11110x101010xxxx0xxxxxxxxxxxxxxx", InstName.Sub, InstEmit32.Sub, OpCodeT32AluImm12.Create);
|
||||||
|
SetT32("111110100100xxxx1111xxxx10xxxxxx", InstName.Sxtb, InstEmit32.Sxtb, OpCodeT32AluUx.Create);
|
||||||
|
SetT32("111110100010xxxx1111xxxx10xxxxxx", InstName.Sxtb16, InstEmit32.Sxtb16, OpCodeT32AluUx.Create);
|
||||||
|
SetT32("111110100000xxxx1111xxxx10xxxxxx", InstName.Sxth, InstEmit32.Sxth, OpCodeT32AluUx.Create);
|
||||||
SetT32("111010001101xxxx111100000000xxxx", InstName.Tbb, InstEmit32.Tbb, OpCodeT32Tb.Create);
|
SetT32("111010001101xxxx111100000000xxxx", InstName.Tbb, InstEmit32.Tbb, OpCodeT32Tb.Create);
|
||||||
SetT32("111010001101xxxx111100000001xxxx", InstName.Tbh, InstEmit32.Tbh, OpCodeT32Tb.Create);
|
SetT32("111010001101xxxx111100000001xxxx", InstName.Tbh, InstEmit32.Tbh, OpCodeT32Tb.Create);
|
||||||
SetT32("111010101001xxxx0xxx1111xxxxxxxx", InstName.Teq, InstEmit32.Teq, OpCodeT32AluRsImm.Create);
|
SetT32("111010101001xxxx0xxx1111xxxxxxxx", InstName.Teq, InstEmit32.Teq, OpCodeT32AluRsImm.Create);
|
||||||
SetT32("11110x001001xxxx0xxx1111xxxxxxxx", InstName.Teq, InstEmit32.Teq, OpCodeT32AluImm.Create);
|
SetT32("11110x001001xxxx0xxx1111xxxxxxxx", InstName.Teq, InstEmit32.Teq, OpCodeT32AluImm.Create);
|
||||||
|
SetT32("11110011101011111000000000010010", InstName.Tsb, InstEmit32.Nop, OpCodeT32.Create); // Trace Synchronization Barrier (FEAT_TRF)
|
||||||
SetT32("111010100001xxxx0xxx1111xxxxxxxx", InstName.Tst, InstEmit32.Tst, OpCodeT32AluRsImm.Create);
|
SetT32("111010100001xxxx0xxx1111xxxxxxxx", InstName.Tst, InstEmit32.Tst, OpCodeT32AluRsImm.Create);
|
||||||
SetT32("11110x000001xxxx0xxx1111xxxxxxxx", InstName.Tst, InstEmit32.Tst, OpCodeT32AluImm.Create);
|
SetT32("11110x000001xxxx0xxx1111xxxxxxxx", InstName.Tst, InstEmit32.Tst, OpCodeT32AluImm.Create);
|
||||||
|
SetT32("111110101000xxxx1111xxxx0100xxxx", InstName.Uadd8, InstEmit32.Uadd8, OpCodeT32AluReg.Create);
|
||||||
|
SetT32("111100111100xxxx0xxxxxxxxx0xxxxx", InstName.Ubfx, InstEmit32.Ubfx, OpCodeT32AluBf.Create);
|
||||||
|
SetT32("111110111011xxxx1111xxxx1111xxxx", InstName.Udiv, InstEmit32.Udiv, OpCodeT32AluMla.Create);
|
||||||
|
SetT32("111110101000xxxx1111xxxx0110xxxx", InstName.Uhadd8, InstEmit32.Uhadd8, OpCodeT32AluReg.Create);
|
||||||
|
SetT32("111110101100xxxx1111xxxx0110xxxx", InstName.Uhsub8, InstEmit32.Uhsub8, OpCodeT32AluReg.Create);
|
||||||
|
SetT32("111110111110xxxxxxxxxxxx0110xxxx", InstName.Umaal, InstEmit32.Umaal, OpCodeT32AluUmull.Create);
|
||||||
|
SetT32("111110111110xxxxxxxxxxxx0000xxxx", InstName.Umlal, InstEmit32.Umlal, OpCodeT32AluUmull.Create);
|
||||||
|
SetT32("111110111010xxxxxxxxxxxx0000xxxx", InstName.Umull, InstEmit32.Umull, OpCodeT32AluUmull.Create);
|
||||||
|
SetT32("111110101100xxxx1111xxxx0100xxxx", InstName.Usub8, InstEmit32.Usub8, OpCodeT32AluReg.Create);
|
||||||
|
SetT32("111110100101xxxx1111xxxx10xxxxxx", InstName.Uxtb, InstEmit32.Uxtb, OpCodeT32AluUx.Create);
|
||||||
|
SetT32("111110100011xxxx1111xxxx10xxxxxx", InstName.Uxtb16, InstEmit32.Uxtb16, OpCodeT32AluUx.Create);
|
||||||
|
SetT32("111110100001xxxx1111xxxx10xxxxxx", InstName.Uxth, InstEmit32.Uxth, OpCodeT32AluUx.Create);
|
||||||
|
SetT32("11110011101011111000000000000010", InstName.Wfe, InstEmit32.Nop, OpCodeT32.Create);
|
||||||
|
SetT32("11110011101011111000000000000011", InstName.Wfi, InstEmit32.Nop, OpCodeT32.Create);
|
||||||
|
SetT32("11110011101011111000000000000001", InstName.Yield, InstEmit32.Nop, OpCodeT32.Create);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
FillFastLookupTable(InstA32FastLookup, AllInstA32, ToFastLookupIndexA);
|
FillFastLookupTable(InstA32FastLookup, AllInstA32, ToFastLookupIndexA);
|
||||||
@@ -1203,6 +1345,46 @@ namespace ARMeilleure.Decoders
|
|||||||
Set(reversedEncoding, AllInstT32, new InstDescriptor(name, emitter), reversedMakeOp);
|
Set(reversedEncoding, AllInstT32, new InstDescriptor(name, emitter), reversedMakeOp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void SetVfp(string encoding, InstName name, InstEmitter emitter, MakeOp makeOpA32, MakeOp makeOpT32)
|
||||||
|
{
|
||||||
|
SetA32(encoding, name, emitter, makeOpA32);
|
||||||
|
|
||||||
|
string thumbEncoding = encoding;
|
||||||
|
if (thumbEncoding.StartsWith("<<<<"))
|
||||||
|
{
|
||||||
|
thumbEncoding = "1110" + thumbEncoding.Substring(4);
|
||||||
|
}
|
||||||
|
SetT32(thumbEncoding, name, emitter, makeOpT32);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SetAsimd(string encoding, InstName name, InstEmitter emitter, MakeOp makeOpA32, MakeOp makeOpT32)
|
||||||
|
{
|
||||||
|
SetA32(encoding, name, emitter, makeOpA32);
|
||||||
|
|
||||||
|
string thumbEncoding = encoding;
|
||||||
|
if (thumbEncoding.StartsWith("11110100"))
|
||||||
|
{
|
||||||
|
thumbEncoding = "11111001" + encoding.Substring(8);
|
||||||
|
}
|
||||||
|
else if (thumbEncoding.StartsWith("1111001x"))
|
||||||
|
{
|
||||||
|
thumbEncoding = "111x1111" + encoding.Substring(8);
|
||||||
|
}
|
||||||
|
else if (thumbEncoding.StartsWith("11110010"))
|
||||||
|
{
|
||||||
|
thumbEncoding = "11101111" + encoding.Substring(8);
|
||||||
|
}
|
||||||
|
else if (thumbEncoding.StartsWith("11110011"))
|
||||||
|
{
|
||||||
|
thumbEncoding = "11111111" + encoding.Substring(8);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Invalid ASIMD instruction encoding");
|
||||||
|
}
|
||||||
|
SetT32(thumbEncoding, name, emitter, makeOpT32);
|
||||||
|
}
|
||||||
|
|
||||||
private static void SetA64(string encoding, InstName name, InstEmitter emitter, MakeOp makeOp)
|
private static void SetA64(string encoding, InstName name, InstEmitter emitter, MakeOp makeOp)
|
||||||
{
|
{
|
||||||
Set(encoding, AllInstA64, new InstDescriptor(name, emitter), makeOp);
|
Set(encoding, AllInstA64, new InstDescriptor(name, emitter), makeOp);
|
||||||
|
@@ -74,7 +74,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void Bfc(ArmEmitterContext context)
|
public static void Bfc(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCode32AluBf op = (OpCode32AluBf)context.CurrOp;
|
IOpCode32AluBf op = (IOpCode32AluBf)context.CurrOp;
|
||||||
|
|
||||||
Operand d = GetIntA32(context, op.Rd);
|
Operand d = GetIntA32(context, op.Rd);
|
||||||
Operand res = context.BitwiseAnd(d, Const(~op.DestMask));
|
Operand res = context.BitwiseAnd(d, Const(~op.DestMask));
|
||||||
@@ -84,7 +84,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void Bfi(ArmEmitterContext context)
|
public static void Bfi(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCode32AluBf op = (OpCode32AluBf)context.CurrOp;
|
IOpCode32AluBf op = (IOpCode32AluBf)context.CurrOp;
|
||||||
|
|
||||||
Operand n = GetIntA32(context, op.Rn);
|
Operand n = GetIntA32(context, op.Rn);
|
||||||
Operand d = GetIntA32(context, op.Rd);
|
Operand d = GetIntA32(context, op.Rd);
|
||||||
@@ -185,7 +185,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void Movt(ArmEmitterContext context)
|
public static void Movt(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCode32AluImm16 op = (OpCode32AluImm16)context.CurrOp;
|
IOpCode32AluImm16 op = (IOpCode32AluImm16)context.CurrOp;
|
||||||
|
|
||||||
Operand d = GetIntA32(context, op.Rd);
|
Operand d = GetIntA32(context, op.Rd);
|
||||||
Operand imm = Const(op.Immediate << 16); // Immeditate value as top halfword.
|
Operand imm = Const(op.Immediate << 16); // Immeditate value as top halfword.
|
||||||
@@ -363,6 +363,11 @@ namespace ARMeilleure.Instructions
|
|||||||
EmitAluStore(context, res);
|
EmitAluStore(context, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Sadd8(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
EmitAddSub8(context, add: true, unsigned: false);
|
||||||
|
}
|
||||||
|
|
||||||
public static void Sbc(ArmEmitterContext context)
|
public static void Sbc(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
|
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
|
||||||
@@ -389,7 +394,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void Sbfx(ArmEmitterContext context)
|
public static void Sbfx(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCode32AluBf op = (OpCode32AluBf)context.CurrOp;
|
IOpCode32AluBf op = (IOpCode32AluBf)context.CurrOp;
|
||||||
|
|
||||||
var msb = op.Lsb + op.Msb; // For this instruction, the msb is actually a width.
|
var msb = op.Lsb + op.Msb; // For this instruction, the msb is actually a width.
|
||||||
|
|
||||||
@@ -401,17 +406,38 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void Sdiv(ArmEmitterContext context)
|
public static void Sdiv(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
EmitDiv(context, false);
|
EmitDiv(context, unsigned: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Sel(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
IOpCode32AluReg op = (IOpCode32AluReg)context.CurrOp;
|
||||||
|
|
||||||
|
Operand n = GetIntA32(context, op.Rn);
|
||||||
|
Operand m = GetIntA32(context, op.Rm);
|
||||||
|
|
||||||
|
Operand ge0 = context.ZeroExtend8(OperandType.I32, context.Negate(GetFlag(PState.GE0Flag)));
|
||||||
|
Operand ge1 = context.ZeroExtend8(OperandType.I32, context.Negate(GetFlag(PState.GE1Flag)));
|
||||||
|
Operand ge2 = context.ZeroExtend8(OperandType.I32, context.Negate(GetFlag(PState.GE2Flag)));
|
||||||
|
Operand ge3 = context.Negate(GetFlag(PState.GE3Flag));
|
||||||
|
|
||||||
|
Operand mask = context.BitwiseOr(ge0, context.ShiftLeft(ge1, Const(8)));
|
||||||
|
mask = context.BitwiseOr(mask, context.ShiftLeft(ge2, Const(16)));
|
||||||
|
mask = context.BitwiseOr(mask, context.ShiftLeft(ge3, Const(24)));
|
||||||
|
|
||||||
|
Operand res = context.BitwiseOr(context.BitwiseAnd(n, mask), context.BitwiseAnd(m, context.BitwiseNot(mask)));
|
||||||
|
|
||||||
|
SetIntA32(context, op.Rd, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Shadd8(ArmEmitterContext context)
|
public static void Shadd8(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
EmitHadd8(context, false);
|
EmitHadd8(context, unsigned: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Shsub8(ArmEmitterContext context)
|
public static void Shsub8(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
EmitHsub8(context, false);
|
EmitHsub8(context, unsigned: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Ssat(ArmEmitterContext context)
|
public static void Ssat(ArmEmitterContext context)
|
||||||
@@ -428,6 +454,11 @@ namespace ARMeilleure.Instructions
|
|||||||
EmitSat16(context, -(1 << op.SatImm), (1 << op.SatImm) - 1);
|
EmitSat16(context, -(1 << op.SatImm), (1 << op.SatImm) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Ssub8(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
EmitAddSub8(context, add: false, unsigned: false);
|
||||||
|
}
|
||||||
|
|
||||||
public static void Sub(ArmEmitterContext context)
|
public static void Sub(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
|
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
|
||||||
@@ -482,9 +513,14 @@ namespace ARMeilleure.Instructions
|
|||||||
EmitNZFlagsCheck(context, res);
|
EmitNZFlagsCheck(context, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Uadd8(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
EmitAddSub8(context, add: true, unsigned: true);
|
||||||
|
}
|
||||||
|
|
||||||
public static void Ubfx(ArmEmitterContext context)
|
public static void Ubfx(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCode32AluBf op = (OpCode32AluBf)context.CurrOp;
|
IOpCode32AluBf op = (IOpCode32AluBf)context.CurrOp;
|
||||||
|
|
||||||
var msb = op.Lsb + op.Msb; // For this instruction, the msb is actually a width.
|
var msb = op.Lsb + op.Msb; // For this instruction, the msb is actually a width.
|
||||||
|
|
||||||
@@ -496,17 +532,17 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void Udiv(ArmEmitterContext context)
|
public static void Udiv(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
EmitDiv(context, true);
|
EmitDiv(context, unsigned: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Uhadd8(ArmEmitterContext context)
|
public static void Uhadd8(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
EmitHadd8(context, true);
|
EmitHadd8(context, unsigned: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Uhsub8(ArmEmitterContext context)
|
public static void Uhsub8(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
EmitHsub8(context, true);
|
EmitHsub8(context, unsigned: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Usat(ArmEmitterContext context)
|
public static void Usat(ArmEmitterContext context)
|
||||||
@@ -523,6 +559,11 @@ namespace ARMeilleure.Instructions
|
|||||||
EmitSat16(context, 0, (1 << op.SatImm) - 1);
|
EmitSat16(context, 0, (1 << op.SatImm) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Usub8(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
EmitAddSub8(context, add: false, unsigned: true);
|
||||||
|
}
|
||||||
|
|
||||||
public static void Uxtb(ArmEmitterContext context)
|
public static void Uxtb(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
EmitSignExtend(context, false, 8);
|
EmitSignExtend(context, false, 8);
|
||||||
@@ -678,9 +719,40 @@ namespace ARMeilleure.Instructions
|
|||||||
context.MarkLabel(lblEnd);
|
context.MarkLabel(lblEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void EmitAddSub8(ArmEmitterContext context, bool add, bool unsigned)
|
||||||
|
{
|
||||||
|
IOpCode32AluReg op = (IOpCode32AluReg)context.CurrOp;
|
||||||
|
|
||||||
|
Operand n = GetIntA32(context, op.Rn);
|
||||||
|
Operand m = GetIntA32(context, op.Rm);
|
||||||
|
|
||||||
|
Operand res = Const(0);
|
||||||
|
|
||||||
|
for (int byteSel = 0; byteSel < 4; byteSel++)
|
||||||
|
{
|
||||||
|
Operand shift = Const(byteSel * 8);
|
||||||
|
|
||||||
|
Operand nByte = context.ShiftRightUI(n, shift);
|
||||||
|
Operand mByte = context.ShiftRightUI(m, shift);
|
||||||
|
|
||||||
|
nByte = unsigned ? context.ZeroExtend8(OperandType.I32, nByte) : context.SignExtend8(OperandType.I32, nByte);
|
||||||
|
mByte = unsigned ? context.ZeroExtend8(OperandType.I32, mByte) : context.SignExtend8(OperandType.I32, mByte);
|
||||||
|
|
||||||
|
Operand resByte = add ? context.Add(nByte, mByte) : context.Subtract(nByte, mByte);
|
||||||
|
|
||||||
|
res = context.BitwiseOr(res, context.ShiftLeft(context.ZeroExtend8(OperandType.I32, resByte), shift));
|
||||||
|
|
||||||
|
SetFlag(context, PState.GE0Flag + byteSel, unsigned && add
|
||||||
|
? context.ShiftRightUI(resByte, Const(8))
|
||||||
|
: context.ShiftRightUI(context.BitwiseNot(resByte), Const(31)));
|
||||||
|
}
|
||||||
|
|
||||||
|
SetIntA32(context, op.Rd, res);
|
||||||
|
}
|
||||||
|
|
||||||
private static void EmitHadd8(ArmEmitterContext context, bool unsigned)
|
private static void EmitHadd8(ArmEmitterContext context, bool unsigned)
|
||||||
{
|
{
|
||||||
OpCode32AluReg op = (OpCode32AluReg)context.CurrOp;
|
IOpCode32AluReg op = (IOpCode32AluReg)context.CurrOp;
|
||||||
|
|
||||||
Operand m = GetIntA32(context, op.Rm);
|
Operand m = GetIntA32(context, op.Rm);
|
||||||
Operand n = GetIntA32(context, op.Rn);
|
Operand n = GetIntA32(context, op.Rn);
|
||||||
@@ -710,7 +782,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
private static void EmitHsub8(ArmEmitterContext context, bool unsigned)
|
private static void EmitHsub8(ArmEmitterContext context, bool unsigned)
|
||||||
{
|
{
|
||||||
OpCode32AluReg op = (OpCode32AluReg)context.CurrOp;
|
IOpCode32AluReg op = (IOpCode32AluReg)context.CurrOp;
|
||||||
|
|
||||||
Operand m = GetIntA32(context, op.Rm);
|
Operand m = GetIntA32(context, op.Rm);
|
||||||
Operand n = GetIntA32(context, op.Rn);
|
Operand n = GetIntA32(context, op.Rn);
|
||||||
|
@@ -128,7 +128,7 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
Debug.Assert(value.Type == OperandType.I32);
|
Debug.Assert(value.Type == OperandType.I32);
|
||||||
|
|
||||||
if (((OpCode32)context.CurrOp).IsThumb())
|
if (((OpCode32)context.CurrOp).IsThumb)
|
||||||
{
|
{
|
||||||
bool isReturn = IsA32Return(context);
|
bool isReturn = IsA32Return(context);
|
||||||
if (!isReturn)
|
if (!isReturn)
|
||||||
@@ -205,7 +205,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return Const(op.Immediate);
|
return Const(op.Immediate);
|
||||||
}
|
}
|
||||||
|
|
||||||
case OpCode32AluImm16 op: return Const(op.Immediate);
|
case IOpCode32AluImm16 op: return Const(op.Immediate);
|
||||||
|
|
||||||
case IOpCode32AluRsImm op: return GetMShiftedByImmediate(context, op, setCarry);
|
case IOpCode32AluRsImm op: return GetMShiftedByImmediate(context, op, setCarry);
|
||||||
case IOpCode32AluRsReg op: return GetMShiftedByReg(context, op, setCarry);
|
case IOpCode32AluRsReg op: return GetMShiftedByReg(context, op, setCarry);
|
||||||
|
@@ -34,7 +34,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
uint pc = op.GetPc();
|
uint pc = op.GetPc();
|
||||||
|
|
||||||
bool isThumb = ((OpCode32)context.CurrOp).IsThumb();
|
bool isThumb = ((OpCode32)context.CurrOp).IsThumb;
|
||||||
|
|
||||||
uint currentPc = isThumb
|
uint currentPc = isThumb
|
||||||
? pc | 1
|
? pc | 1
|
||||||
@@ -61,7 +61,7 @@ namespace ARMeilleure.Instructions
|
|||||||
Operand addr = context.Copy(GetIntA32(context, op.Rm));
|
Operand addr = context.Copy(GetIntA32(context, op.Rm));
|
||||||
Operand bitOne = context.BitwiseAnd(addr, Const(1));
|
Operand bitOne = context.BitwiseAnd(addr, Const(1));
|
||||||
|
|
||||||
bool isThumb = ((OpCode32)context.CurrOp).IsThumb();
|
bool isThumb = ((OpCode32)context.CurrOp).IsThumb;
|
||||||
|
|
||||||
uint currentPc = isThumb
|
uint currentPc = isThumb
|
||||||
? (pc - 2) | 1
|
? (pc - 2) | 1
|
||||||
|
@@ -26,6 +26,11 @@ namespace ARMeilleure.Instructions
|
|||||||
EmitClearExclusive(context);
|
EmitClearExclusive(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Csdb(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
// Execute as no-op.
|
||||||
|
}
|
||||||
|
|
||||||
public static void Dmb(ArmEmitterContext context) => EmitBarrier(context);
|
public static void Dmb(ArmEmitterContext context) => EmitBarrier(context);
|
||||||
public static void Dsb(ArmEmitterContext context) => EmitBarrier(context);
|
public static void Dsb(ArmEmitterContext context) => EmitBarrier(context);
|
||||||
|
|
||||||
|
@@ -172,13 +172,13 @@ namespace ARMeilleure.Instructions
|
|||||||
context.BranchIfTrue(lblBigEndian, GetFlag(PState.EFlag));
|
context.BranchIfTrue(lblBigEndian, GetFlag(PState.EFlag));
|
||||||
|
|
||||||
SetIntA32(context, op.Rt, valueLow);
|
SetIntA32(context, op.Rt, valueLow);
|
||||||
SetIntA32(context, op.Rt | 1, valueHigh);
|
SetIntA32(context, op.Rt2, valueHigh);
|
||||||
|
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
context.MarkLabel(lblBigEndian);
|
context.MarkLabel(lblBigEndian);
|
||||||
|
|
||||||
SetIntA32(context, op.Rt | 1, valueLow);
|
SetIntA32(context, op.Rt2, valueLow);
|
||||||
SetIntA32(context, op.Rt, valueHigh);
|
SetIntA32(context, op.Rt, valueHigh);
|
||||||
|
|
||||||
context.MarkLabel(lblEnd);
|
context.MarkLabel(lblEnd);
|
||||||
@@ -195,7 +195,7 @@ namespace ARMeilleure.Instructions
|
|||||||
// Split the result into 2 words (based on endianness)
|
// Split the result into 2 words (based on endianness)
|
||||||
|
|
||||||
Operand lo = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rt));
|
Operand lo = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rt));
|
||||||
Operand hi = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rt | 1));
|
Operand hi = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rt2));
|
||||||
|
|
||||||
Operand lblBigEndian = Label();
|
Operand lblBigEndian = Label();
|
||||||
Operand lblEnd = Label();
|
Operand lblEnd = Label();
|
||||||
|
@@ -25,7 +25,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void Mla(ArmEmitterContext context)
|
public static void Mla(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCode32AluMla op = (OpCode32AluMla)context.CurrOp;
|
IOpCode32AluMla op = (IOpCode32AluMla)context.CurrOp;
|
||||||
|
|
||||||
Operand n = GetAluN(context);
|
Operand n = GetAluN(context);
|
||||||
Operand m = GetAluM(context);
|
Operand m = GetAluM(context);
|
||||||
@@ -43,7 +43,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void Mls(ArmEmitterContext context)
|
public static void Mls(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCode32AluMla op = (OpCode32AluMla)context.CurrOp;
|
IOpCode32AluMla op = (IOpCode32AluMla)context.CurrOp;
|
||||||
|
|
||||||
Operand n = GetAluN(context);
|
Operand n = GetAluN(context);
|
||||||
Operand m = GetAluM(context);
|
Operand m = GetAluM(context);
|
||||||
@@ -71,7 +71,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
private static void EmitSmmul(ArmEmitterContext context, MullFlags flags)
|
private static void EmitSmmul(ArmEmitterContext context, MullFlags flags)
|
||||||
{
|
{
|
||||||
OpCode32AluMla op = (OpCode32AluMla)context.CurrOp;
|
IOpCode32AluMla op = (IOpCode32AluMla)context.CurrOp;
|
||||||
|
|
||||||
Operand n = context.SignExtend32(OperandType.I64, GetIntA32(context, op.Rn));
|
Operand n = context.SignExtend32(OperandType.I64, GetIntA32(context, op.Rn));
|
||||||
Operand m = context.SignExtend32(OperandType.I64, GetIntA32(context, op.Rm));
|
Operand m = context.SignExtend32(OperandType.I64, GetIntA32(context, op.Rm));
|
||||||
@@ -99,7 +99,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void Smla__(ArmEmitterContext context)
|
public static void Smla__(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCode32AluMla op = (OpCode32AluMla)context.CurrOp;
|
IOpCode32AluMla op = (IOpCode32AluMla)context.CurrOp;
|
||||||
|
|
||||||
Operand n = GetIntA32(context, op.Rn);
|
Operand n = GetIntA32(context, op.Rn);
|
||||||
Operand m = GetIntA32(context, op.Rm);
|
Operand m = GetIntA32(context, op.Rm);
|
||||||
@@ -142,7 +142,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void Smlal__(ArmEmitterContext context)
|
public static void Smlal__(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCode32AluUmull op = (OpCode32AluUmull)context.CurrOp;
|
IOpCode32AluUmull op = (IOpCode32AluUmull)context.CurrOp;
|
||||||
|
|
||||||
Operand n = GetIntA32(context, op.Rn);
|
Operand n = GetIntA32(context, op.Rn);
|
||||||
Operand m = GetIntA32(context, op.Rm);
|
Operand m = GetIntA32(context, op.Rm);
|
||||||
@@ -180,7 +180,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void Smlaw_(ArmEmitterContext context)
|
public static void Smlaw_(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCode32AluMla op = (OpCode32AluMla)context.CurrOp;
|
IOpCode32AluMla op = (IOpCode32AluMla)context.CurrOp;
|
||||||
|
|
||||||
Operand n = GetIntA32(context, op.Rn);
|
Operand n = GetIntA32(context, op.Rn);
|
||||||
Operand m = GetIntA32(context, op.Rm);
|
Operand m = GetIntA32(context, op.Rm);
|
||||||
@@ -210,7 +210,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void Smul__(ArmEmitterContext context)
|
public static void Smul__(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCode32AluMla op = (OpCode32AluMla)context.CurrOp;
|
IOpCode32AluMla op = (IOpCode32AluMla)context.CurrOp;
|
||||||
|
|
||||||
Operand n = GetIntA32(context, op.Rn);
|
Operand n = GetIntA32(context, op.Rn);
|
||||||
Operand m = GetIntA32(context, op.Rm);
|
Operand m = GetIntA32(context, op.Rm);
|
||||||
@@ -240,7 +240,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void Smull(ArmEmitterContext context)
|
public static void Smull(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCode32AluUmull op = (OpCode32AluUmull)context.CurrOp;
|
IOpCode32AluUmull op = (IOpCode32AluUmull)context.CurrOp;
|
||||||
|
|
||||||
Operand n = context.SignExtend32(OperandType.I64, GetIntA32(context, op.Rn));
|
Operand n = context.SignExtend32(OperandType.I64, GetIntA32(context, op.Rn));
|
||||||
Operand m = context.SignExtend32(OperandType.I64, GetIntA32(context, op.Rm));
|
Operand m = context.SignExtend32(OperandType.I64, GetIntA32(context, op.Rm));
|
||||||
@@ -261,7 +261,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void Smulw_(ArmEmitterContext context)
|
public static void Smulw_(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCode32AluMla op = (OpCode32AluMla)context.CurrOp;
|
IOpCode32AluMla op = (IOpCode32AluMla)context.CurrOp;
|
||||||
|
|
||||||
Operand n = GetIntA32(context, op.Rn);
|
Operand n = GetIntA32(context, op.Rn);
|
||||||
Operand m = GetIntA32(context, op.Rm);
|
Operand m = GetIntA32(context, op.Rm);
|
||||||
@@ -285,7 +285,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void Umaal(ArmEmitterContext context)
|
public static void Umaal(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCode32AluUmull op = (OpCode32AluUmull)context.CurrOp;
|
IOpCode32AluUmull op = (IOpCode32AluUmull)context.CurrOp;
|
||||||
|
|
||||||
Operand n = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rn));
|
Operand n = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rn));
|
||||||
Operand m = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rm));
|
Operand m = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rm));
|
||||||
@@ -310,7 +310,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void Umull(ArmEmitterContext context)
|
public static void Umull(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCode32AluUmull op = (OpCode32AluUmull)context.CurrOp;
|
IOpCode32AluUmull op = (IOpCode32AluUmull)context.CurrOp;
|
||||||
|
|
||||||
Operand n = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rn));
|
Operand n = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rn));
|
||||||
Operand m = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rm));
|
Operand m = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rm));
|
||||||
@@ -331,7 +331,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
private static void EmitMlal(ArmEmitterContext context, bool signed)
|
private static void EmitMlal(ArmEmitterContext context, bool signed)
|
||||||
{
|
{
|
||||||
OpCode32AluUmull op = (OpCode32AluUmull)context.CurrOp;
|
IOpCode32AluUmull op = (IOpCode32AluUmull)context.CurrOp;
|
||||||
|
|
||||||
Operand n = GetIntA32(context, op.Rn);
|
Operand n = GetIntA32(context, op.Rn);
|
||||||
Operand m = GetIntA32(context, op.Rm);
|
Operand m = GetIntA32(context, op.Rm);
|
||||||
|
@@ -323,6 +323,60 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VRINTA (vector).
|
||||||
|
public static void Vrinta_V(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
EmitVectorUnaryOpF32(context, (m) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, m));
|
||||||
|
}
|
||||||
|
|
||||||
|
// VRINTM (vector).
|
||||||
|
public static void Vrintm_V(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
if (Optimizations.UseSse2)
|
||||||
|
{
|
||||||
|
EmitVectorUnaryOpSimd32(context, (m) =>
|
||||||
|
{
|
||||||
|
return context.AddIntrinsic(Intrinsic.X86Roundps, m, Const(X86GetRoundControl(FPRoundingMode.TowardsMinusInfinity)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitVectorUnaryOpF32(context, (m) => EmitUnaryMathCall(context, nameof(Math.Floor), m));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// VRINTN (vector).
|
||||||
|
public static void Vrintn_V(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
if (Optimizations.UseSse2)
|
||||||
|
{
|
||||||
|
EmitVectorUnaryOpSimd32(context, (m) =>
|
||||||
|
{
|
||||||
|
return context.AddIntrinsic(Intrinsic.X86Roundps, m, Const(X86GetRoundControl(FPRoundingMode.ToNearest)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitVectorUnaryOpF32(context, (m) => EmitRoundMathCall(context, MidpointRounding.ToEven, m));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// VRINTP (vector).
|
||||||
|
public static void Vrintp_V(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
if (Optimizations.UseSse2)
|
||||||
|
{
|
||||||
|
EmitVectorUnaryOpSimd32(context, (m) =>
|
||||||
|
{
|
||||||
|
return context.AddIntrinsic(Intrinsic.X86Roundps, m, Const(X86GetRoundControl(FPRoundingMode.TowardsPlusInfinity)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitVectorUnaryOpF32(context, (m) => EmitUnaryMathCall(context, nameof(Math.Ceiling), m));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// VRINTZ (floating-point).
|
// VRINTZ (floating-point).
|
||||||
public static void Vrint_Z(ArmEmitterContext context)
|
public static void Vrint_Z(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
|
@@ -1533,29 +1533,88 @@ namespace ARMeilleure.Instructions
|
|||||||
context.Copy(d, res);
|
context.Copy(d, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TSrc (16bit, 32bit, 64bit; signed) > TDst (8bit, 16bit, 32bit; signed, unsigned).
|
// long SignedSignSatQ(long op, int size);
|
||||||
// long SignedSrcSignedDstSatQ(long op, int size); ulong SignedSrcUnsignedDstSatQ(long op, int size);
|
public static Operand EmitSignedSignSatQ(ArmEmitterContext context, Operand op, int size)
|
||||||
public static Operand EmitSignedSrcSatQ(ArmEmitterContext context, Operand op, int sizeDst, bool signedDst)
|
|
||||||
{
|
{
|
||||||
Debug.Assert(op.Type == OperandType.I64 && (uint)sizeDst <= 2u);
|
int eSize = 8 << size;
|
||||||
|
|
||||||
|
Debug.Assert(op.Type == OperandType.I64);
|
||||||
|
Debug.Assert(eSize == 8 || eSize == 16 || eSize == 32 || eSize == 64);
|
||||||
|
|
||||||
Operand lbl1 = Label();
|
Operand lbl1 = Label();
|
||||||
Operand lblEnd = Label();
|
Operand lblEnd = Label();
|
||||||
|
|
||||||
int eSize = 8 << sizeDst;
|
Operand zeroL = Const(0L);
|
||||||
|
Operand maxT = Const((1L << (eSize - 1)) - 1L);
|
||||||
|
Operand minT = Const(-(1L << (eSize - 1)));
|
||||||
|
|
||||||
Operand maxT = signedDst ? Const((1L << (eSize - 1)) - 1L) : Const((1UL << eSize) - 1UL);
|
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), zeroL);
|
||||||
Operand minT = signedDst ? Const(-(1L << (eSize - 1))) : Const(0UL);
|
|
||||||
|
|
||||||
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op);
|
context.BranchIf(lbl1, op, zeroL, Comparison.LessOrEqual);
|
||||||
|
|
||||||
context.BranchIf(lbl1, res, maxT, Comparison.LessOrEqual);
|
|
||||||
context.Copy(res, maxT);
|
context.Copy(res, maxT);
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
context.MarkLabel(lbl1);
|
context.MarkLabel(lbl1);
|
||||||
context.BranchIf(lblEnd, res, minT, Comparison.GreaterOrEqual);
|
context.BranchIf(lblEnd, op, zeroL, Comparison.GreaterOrEqual);
|
||||||
|
context.Copy(res, minT);
|
||||||
|
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||||
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
|
context.MarkLabel(lblEnd);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// private static ulong UnsignedSignSatQ(ulong op, int size);
|
||||||
|
public static Operand EmitUnsignedSignSatQ(ArmEmitterContext context, Operand op, int size)
|
||||||
|
{
|
||||||
|
int eSize = 8 << size;
|
||||||
|
|
||||||
|
Debug.Assert(op.Type == OperandType.I64);
|
||||||
|
Debug.Assert(eSize == 8 || eSize == 16 || eSize == 32 || eSize == 64);
|
||||||
|
|
||||||
|
Operand lblEnd = Label();
|
||||||
|
|
||||||
|
Operand zeroUL = Const(0UL);
|
||||||
|
Operand maxT = Const(ulong.MaxValue >> (64 - eSize));
|
||||||
|
|
||||||
|
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), zeroUL);
|
||||||
|
|
||||||
|
context.BranchIf(lblEnd, op, zeroUL, Comparison.LessOrEqualUI);
|
||||||
|
context.Copy(res, maxT);
|
||||||
|
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||||
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
|
context.MarkLabel(lblEnd);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TSrc (16bit, 32bit, 64bit; signed) > TDst (8bit, 16bit, 32bit; signed, unsigned).
|
||||||
|
// long SignedSrcSignedDstSatQ(long op, int size); ulong SignedSrcUnsignedDstSatQ(long op, int size);
|
||||||
|
public static Operand EmitSignedSrcSatQ(ArmEmitterContext context, Operand op, int sizeDst, bool signedDst)
|
||||||
|
{
|
||||||
|
int eSizeDst = 8 << sizeDst;
|
||||||
|
|
||||||
|
Debug.Assert(op.Type == OperandType.I64);
|
||||||
|
Debug.Assert(eSizeDst == 8 || eSizeDst == 16 || eSizeDst == 32);
|
||||||
|
|
||||||
|
Operand lbl1 = Label();
|
||||||
|
Operand lblEnd = Label();
|
||||||
|
|
||||||
|
Operand maxT = signedDst ? Const((1L << (eSizeDst - 1)) - 1L) : Const((1UL << eSizeDst) - 1UL);
|
||||||
|
Operand minT = signedDst ? Const(-(1L << (eSizeDst - 1))) : Const(0UL);
|
||||||
|
|
||||||
|
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op);
|
||||||
|
|
||||||
|
context.BranchIf(lbl1, op, maxT, Comparison.LessOrEqual);
|
||||||
|
context.Copy(res, maxT);
|
||||||
|
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||||
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
|
context.MarkLabel(lbl1);
|
||||||
|
context.BranchIf(lblEnd, op, minT, Comparison.GreaterOrEqual);
|
||||||
context.Copy(res, minT);
|
context.Copy(res, minT);
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
@@ -1569,18 +1628,19 @@ namespace ARMeilleure.Instructions
|
|||||||
// long UnsignedSrcSignedDstSatQ(ulong op, int size); ulong UnsignedSrcUnsignedDstSatQ(ulong op, int size);
|
// long UnsignedSrcSignedDstSatQ(ulong op, int size); ulong UnsignedSrcUnsignedDstSatQ(ulong op, int size);
|
||||||
public static Operand EmitUnsignedSrcSatQ(ArmEmitterContext context, Operand op, int sizeDst, bool signedDst)
|
public static Operand EmitUnsignedSrcSatQ(ArmEmitterContext context, Operand op, int sizeDst, bool signedDst)
|
||||||
{
|
{
|
||||||
Debug.Assert(op.Type == OperandType.I64 && (uint)sizeDst <= 2u);
|
int eSizeDst = 8 << sizeDst;
|
||||||
|
|
||||||
|
Debug.Assert(op.Type == OperandType.I64);
|
||||||
|
Debug.Assert(eSizeDst == 8 || eSizeDst == 16 || eSizeDst == 32);
|
||||||
|
|
||||||
Operand lblEnd = Label();
|
Operand lblEnd = Label();
|
||||||
|
|
||||||
int eSize = 8 << sizeDst;
|
Operand maxT = signedDst ? Const((1L << (eSizeDst - 1)) - 1L) : Const((1UL << eSizeDst) - 1UL);
|
||||||
|
|
||||||
Operand maxL = signedDst ? Const((1L << (eSize - 1)) - 1L) : Const((1UL << eSize) - 1UL);
|
|
||||||
|
|
||||||
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op);
|
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op);
|
||||||
|
|
||||||
context.BranchIf(lblEnd, res, maxL, Comparison.LessOrEqualUI);
|
context.BranchIf(lblEnd, op, maxT, Comparison.LessOrEqualUI);
|
||||||
context.Copy(res, maxL);
|
context.Copy(res, maxT);
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
@@ -1601,7 +1661,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op);
|
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op);
|
||||||
|
|
||||||
context.BranchIf(lblEnd, res, minL, Comparison.NotEqual);
|
context.BranchIf(lblEnd, op, minL, Comparison.NotEqual);
|
||||||
context.Copy(res, maxL);
|
context.Copy(res, maxL);
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
@@ -1620,15 +1680,16 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand minL = Const(long.MinValue);
|
Operand minL = Const(long.MinValue);
|
||||||
Operand maxL = Const(long.MaxValue);
|
Operand maxL = Const(long.MaxValue);
|
||||||
Operand zero = Const(0L);
|
Operand zeroL = Const(0L);
|
||||||
|
|
||||||
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), context.Add(op1, op2));
|
Operand add = context.Add(op1, op2);
|
||||||
|
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), add);
|
||||||
|
|
||||||
Operand left = context.BitwiseNot(context.BitwiseExclusiveOr(op1, op2));
|
Operand left = context.BitwiseNot(context.BitwiseExclusiveOr(op1, op2));
|
||||||
Operand right = context.BitwiseExclusiveOr(op1, res);
|
Operand right = context.BitwiseExclusiveOr(op1, add);
|
||||||
context.BranchIf(lblEnd, context.BitwiseAnd(left, right), zero, Comparison.GreaterOrEqual);
|
context.BranchIf(lblEnd, context.BitwiseAnd(left, right), zeroL, Comparison.GreaterOrEqual);
|
||||||
|
|
||||||
Operand isPositive = context.ICompareGreaterOrEqual(op1, zero);
|
Operand isPositive = context.ICompareGreaterOrEqual(op1, zeroL);
|
||||||
context.Copy(res, context.ConditionalSelect(isPositive, maxL, minL));
|
context.Copy(res, context.ConditionalSelect(isPositive, maxL, minL));
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
@@ -1647,9 +1708,10 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand maxUL = Const(ulong.MaxValue);
|
Operand maxUL = Const(ulong.MaxValue);
|
||||||
|
|
||||||
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), context.Add(op1, op2));
|
Operand add = context.Add(op1, op2);
|
||||||
|
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), add);
|
||||||
|
|
||||||
context.BranchIf(lblEnd, res, op1, Comparison.GreaterOrEqualUI);
|
context.BranchIf(lblEnd, add, op1, Comparison.GreaterOrEqualUI);
|
||||||
context.Copy(res, maxUL);
|
context.Copy(res, maxUL);
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
@@ -1668,15 +1730,16 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand minL = Const(long.MinValue);
|
Operand minL = Const(long.MinValue);
|
||||||
Operand maxL = Const(long.MaxValue);
|
Operand maxL = Const(long.MaxValue);
|
||||||
Operand zero = Const(0L);
|
Operand zeroL = Const(0L);
|
||||||
|
|
||||||
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), context.Subtract(op1, op2));
|
Operand sub = context.Subtract(op1, op2);
|
||||||
|
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), sub);
|
||||||
|
|
||||||
Operand left = context.BitwiseExclusiveOr(op1, op2);
|
Operand left = context.BitwiseExclusiveOr(op1, op2);
|
||||||
Operand right = context.BitwiseExclusiveOr(op1, res);
|
Operand right = context.BitwiseExclusiveOr(op1, sub);
|
||||||
context.BranchIf(lblEnd, context.BitwiseAnd(left, right), zero, Comparison.GreaterOrEqual);
|
context.BranchIf(lblEnd, context.BitwiseAnd(left, right), zeroL, Comparison.GreaterOrEqual);
|
||||||
|
|
||||||
Operand isPositive = context.ICompareGreaterOrEqual(op1, zero);
|
Operand isPositive = context.ICompareGreaterOrEqual(op1, zeroL);
|
||||||
context.Copy(res, context.ConditionalSelect(isPositive, maxL, minL));
|
context.Copy(res, context.ConditionalSelect(isPositive, maxL, minL));
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
@@ -1693,12 +1756,13 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand lblEnd = Label();
|
Operand lblEnd = Label();
|
||||||
|
|
||||||
Operand zero = Const(0L);
|
Operand zeroL = Const(0L);
|
||||||
|
|
||||||
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), context.Subtract(op1, op2));
|
Operand sub = context.Subtract(op1, op2);
|
||||||
|
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), sub);
|
||||||
|
|
||||||
context.BranchIf(lblEnd, op1, op2, Comparison.GreaterOrEqualUI);
|
context.BranchIf(lblEnd, op1, op2, Comparison.GreaterOrEqualUI);
|
||||||
context.Copy(res, zero);
|
context.Copy(res, zeroL);
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
@@ -1717,25 +1781,26 @@ namespace ARMeilleure.Instructions
|
|||||||
Operand lblEnd = Label();
|
Operand lblEnd = Label();
|
||||||
|
|
||||||
Operand maxL = Const(long.MaxValue);
|
Operand maxL = Const(long.MaxValue);
|
||||||
Operand zero = Const(0L);
|
Operand zeroL = Const(0L);
|
||||||
|
|
||||||
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), context.Add(op1, op2));
|
Operand add = context.Add(op1, op2);
|
||||||
|
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), add);
|
||||||
|
|
||||||
context.BranchIf(lbl1, op1, maxL, Comparison.GreaterUI);
|
context.BranchIf(lbl1, op1, maxL, Comparison.GreaterUI);
|
||||||
Operand notOp2AndRes = context.BitwiseAnd(context.BitwiseNot(op2), res);
|
Operand notOp2AndRes = context.BitwiseAnd(context.BitwiseNot(op2), add);
|
||||||
context.BranchIf(lblEnd, notOp2AndRes, zero, Comparison.GreaterOrEqual);
|
context.BranchIf(lblEnd, notOp2AndRes, zeroL, Comparison.GreaterOrEqual);
|
||||||
context.Copy(res, maxL);
|
context.Copy(res, maxL);
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
context.MarkLabel(lbl1);
|
context.MarkLabel(lbl1);
|
||||||
context.BranchIf(lbl2, op2, zero, Comparison.Less);
|
context.BranchIf(lbl2, op2, zeroL, Comparison.Less);
|
||||||
context.Copy(res, maxL);
|
context.Copy(res, maxL);
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
context.MarkLabel(lbl2);
|
context.MarkLabel(lbl2);
|
||||||
context.BranchIf(lblEnd, res, maxL, Comparison.LessOrEqualUI);
|
context.BranchIf(lblEnd, add, maxL, Comparison.LessOrEqualUI);
|
||||||
context.Copy(res, maxL);
|
context.Copy(res, maxL);
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
@@ -1755,20 +1820,21 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand maxUL = Const(ulong.MaxValue);
|
Operand maxUL = Const(ulong.MaxValue);
|
||||||
Operand maxL = Const(long.MaxValue);
|
Operand maxL = Const(long.MaxValue);
|
||||||
Operand zero = Const(0L);
|
Operand zeroL = Const(0L);
|
||||||
|
|
||||||
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), context.Add(op1, op2));
|
Operand add = context.Add(op1, op2);
|
||||||
|
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), add);
|
||||||
|
|
||||||
context.BranchIf(lbl1, op1, zero, Comparison.Less);
|
context.BranchIf(lbl1, op1, zeroL, Comparison.Less);
|
||||||
context.BranchIf(lblEnd, res, op1, Comparison.GreaterOrEqualUI);
|
context.BranchIf(lblEnd, add, op1, Comparison.GreaterOrEqualUI);
|
||||||
context.Copy(res, maxUL);
|
context.Copy(res, maxUL);
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
context.MarkLabel(lbl1);
|
context.MarkLabel(lbl1);
|
||||||
context.BranchIf(lblEnd, op2, maxL, Comparison.GreaterUI);
|
context.BranchIf(lblEnd, op2, maxL, Comparison.GreaterUI);
|
||||||
context.BranchIf(lblEnd, res, zero, Comparison.GreaterOrEqual);
|
context.BranchIf(lblEnd, add, zeroL, Comparison.GreaterOrEqual);
|
||||||
context.Copy(res, zero);
|
context.Copy(res, zeroL);
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
|
@@ -67,7 +67,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
// Write an element from a double simd register.
|
// Accesses an element from a double simd register.
|
||||||
Operand address = context.Add(n, Const(offset));
|
Operand address = context.Add(n, Const(offset));
|
||||||
if (eBytes == 8)
|
if (eBytes == 8)
|
||||||
{
|
{
|
||||||
@@ -131,6 +131,7 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
OpCode32SimdMemPair op = (OpCode32SimdMemPair)context.CurrOp;
|
OpCode32SimdMemPair op = (OpCode32SimdMemPair)context.CurrOp;
|
||||||
|
|
||||||
|
int increment = count > 1 ? op.Increment : 1;
|
||||||
int eBytes = 1 << op.Size;
|
int eBytes = 1 << op.Size;
|
||||||
|
|
||||||
Operand n = context.Copy(GetIntA32(context, op.Rn));
|
Operand n = context.Copy(GetIntA32(context, op.Rn));
|
||||||
@@ -144,7 +145,7 @@ namespace ARMeilleure.Instructions
|
|||||||
int elemD = d + reg;
|
int elemD = d + reg;
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
// Write an element from a double simd register
|
// Accesses an element from a double simd register,
|
||||||
// add ebytes for each element.
|
// add ebytes for each element.
|
||||||
Operand address = context.Add(n, Const(offset));
|
Operand address = context.Add(n, Const(offset));
|
||||||
int index = ((elemD & 1) << (3 - op.Size)) + elem;
|
int index = ((elemD & 1) << (3 - op.Size)) + elem;
|
||||||
@@ -161,7 +162,6 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
if (load)
|
if (load)
|
||||||
{
|
{
|
||||||
EmitLoadSimd(context, address, GetVecA32(elemD >> 1), elemD >> 1, index, op.Size);
|
EmitLoadSimd(context, address, GetVecA32(elemD >> 1), elemD >> 1, index, op.Size);
|
||||||
@@ -173,7 +173,7 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
|
|
||||||
offset += eBytes;
|
offset += eBytes;
|
||||||
elemD += op.Increment;
|
elemD += increment;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -188,23 +188,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void Sqrshl_V(ArmEmitterContext context)
|
public static void Sqrshl_V(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
|
EmitShlRegOp(context, ShlRegFlags.Signed | ShlRegFlags.Round | ShlRegFlags.Saturating);
|
||||||
|
|
||||||
Operand res = context.VectorZero();
|
|
||||||
|
|
||||||
int elems = op.GetBytesCount() >> op.Size;
|
|
||||||
|
|
||||||
for (int index = 0; index < elems; index++)
|
|
||||||
{
|
|
||||||
Operand ne = EmitVectorExtractSx(context, op.Rn, index, op.Size);
|
|
||||||
Operand me = EmitVectorExtractSx(context, op.Rm, index, op.Size);
|
|
||||||
|
|
||||||
Operand e = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShlRegSatQ)), ne, me, Const(1), Const(op.Size));
|
|
||||||
|
|
||||||
res = EmitVectorInsert(context, res, e, index, op.Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.Copy(GetVec(op.Rd), res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Sqrshrn_S(ArmEmitterContext context)
|
public static void Sqrshrn_S(ArmEmitterContext context)
|
||||||
@@ -229,23 +213,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void Sqshl_V(ArmEmitterContext context)
|
public static void Sqshl_V(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
|
EmitShlRegOp(context, ShlRegFlags.Signed | ShlRegFlags.Saturating);
|
||||||
|
|
||||||
Operand res = context.VectorZero();
|
|
||||||
|
|
||||||
int elems = op.GetBytesCount() >> op.Size;
|
|
||||||
|
|
||||||
for (int index = 0; index < elems; index++)
|
|
||||||
{
|
|
||||||
Operand ne = EmitVectorExtractSx(context, op.Rn, index, op.Size);
|
|
||||||
Operand me = EmitVectorExtractSx(context, op.Rm, index, op.Size);
|
|
||||||
|
|
||||||
Operand e = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShlRegSatQ)), ne, me, Const(0), Const(op.Size));
|
|
||||||
|
|
||||||
res = EmitVectorInsert(context, res, e, index, op.Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.Copy(GetVec(op.Rd), res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Sqshrn_S(ArmEmitterContext context)
|
public static void Sqshrn_S(ArmEmitterContext context)
|
||||||
@@ -280,23 +248,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void Srshl_V(ArmEmitterContext context)
|
public static void Srshl_V(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
|
EmitShlRegOp(context, ShlRegFlags.Signed | ShlRegFlags.Round);
|
||||||
|
|
||||||
Operand res = context.VectorZero();
|
|
||||||
|
|
||||||
int elems = op.GetBytesCount() >> op.Size;
|
|
||||||
|
|
||||||
for (int index = 0; index < elems; index++)
|
|
||||||
{
|
|
||||||
Operand ne = EmitVectorExtractSx(context, op.Rn, index, op.Size);
|
|
||||||
Operand me = EmitVectorExtractSx(context, op.Rm, index, op.Size);
|
|
||||||
|
|
||||||
Operand e = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShlReg)), ne, me, Const(1), Const(op.Size));
|
|
||||||
|
|
||||||
res = EmitVectorInsert(context, res, e, index, op.Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.Copy(GetVec(op.Rd), res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Srshr_S(ArmEmitterContext context)
|
public static void Srshr_S(ArmEmitterContext context)
|
||||||
@@ -393,12 +345,12 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void Sshl_S(ArmEmitterContext context)
|
public static void Sshl_S(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
EmitSshlOrUshl(context, signed: true, scalar: true);
|
EmitShlRegOp(context, ShlRegFlags.Scalar | ShlRegFlags.Signed);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Sshl_V(ArmEmitterContext context)
|
public static void Sshl_V(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
EmitSshlOrUshl(context, signed: true, scalar: false);
|
EmitShlRegOp(context, ShlRegFlags.Signed);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Sshll_V(ArmEmitterContext context)
|
public static void Sshll_V(ArmEmitterContext context)
|
||||||
@@ -506,23 +458,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void Uqrshl_V(ArmEmitterContext context)
|
public static void Uqrshl_V(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
|
EmitShlRegOp(context, ShlRegFlags.Round | ShlRegFlags.Saturating);
|
||||||
|
|
||||||
Operand res = context.VectorZero();
|
|
||||||
|
|
||||||
int elems = op.GetBytesCount() >> op.Size;
|
|
||||||
|
|
||||||
for (int index = 0; index < elems; index++)
|
|
||||||
{
|
|
||||||
Operand ne = EmitVectorExtractZx(context, op.Rn, index, op.Size);
|
|
||||||
Operand me = EmitVectorExtractZx(context, op.Rm, index, op.Size);
|
|
||||||
|
|
||||||
Operand e = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShlRegSatQ)), ne, me, Const(1), Const(op.Size));
|
|
||||||
|
|
||||||
res = EmitVectorInsert(context, res, e, index, op.Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.Copy(GetVec(op.Rd), res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Uqrshrn_S(ArmEmitterContext context)
|
public static void Uqrshrn_S(ArmEmitterContext context)
|
||||||
@@ -537,23 +473,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void Uqshl_V(ArmEmitterContext context)
|
public static void Uqshl_V(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
|
EmitShlRegOp(context, ShlRegFlags.Saturating);
|
||||||
|
|
||||||
Operand res = context.VectorZero();
|
|
||||||
|
|
||||||
int elems = op.GetBytesCount() >> op.Size;
|
|
||||||
|
|
||||||
for (int index = 0; index < elems; index++)
|
|
||||||
{
|
|
||||||
Operand ne = EmitVectorExtractZx(context, op.Rn, index, op.Size);
|
|
||||||
Operand me = EmitVectorExtractZx(context, op.Rm, index, op.Size);
|
|
||||||
|
|
||||||
Operand e = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShlRegSatQ)), ne, me, Const(0), Const(op.Size));
|
|
||||||
|
|
||||||
res = EmitVectorInsert(context, res, e, index, op.Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.Copy(GetVec(op.Rd), res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Uqshrn_S(ArmEmitterContext context)
|
public static void Uqshrn_S(ArmEmitterContext context)
|
||||||
@@ -568,23 +488,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void Urshl_V(ArmEmitterContext context)
|
public static void Urshl_V(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
|
EmitShlRegOp(context, ShlRegFlags.Round);
|
||||||
|
|
||||||
Operand res = context.VectorZero();
|
|
||||||
|
|
||||||
int elems = op.GetBytesCount() >> op.Size;
|
|
||||||
|
|
||||||
for (int index = 0; index < elems; index++)
|
|
||||||
{
|
|
||||||
Operand ne = EmitVectorExtractZx(context, op.Rn, index, op.Size);
|
|
||||||
Operand me = EmitVectorExtractZx(context, op.Rm, index, op.Size);
|
|
||||||
|
|
||||||
Operand e = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShlReg)), ne, me, Const(1), Const(op.Size));
|
|
||||||
|
|
||||||
res = EmitVectorInsert(context, res, e, index, op.Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.Copy(GetVec(op.Rd), res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Urshr_S(ArmEmitterContext context)
|
public static void Urshr_S(ArmEmitterContext context)
|
||||||
@@ -677,12 +581,12 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void Ushl_S(ArmEmitterContext context)
|
public static void Ushl_S(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
EmitSshlOrUshl(context, signed: false, scalar: true);
|
EmitShlRegOp(context, ShlRegFlags.Scalar);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Ushl_V(ArmEmitterContext context)
|
public static void Ushl_V(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
EmitSshlOrUshl(context, signed: false, scalar: false);
|
EmitShlRegOp(context, ShlRegFlags.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Ushll_V(ArmEmitterContext context)
|
public static void Ushll_V(ArmEmitterContext context)
|
||||||
@@ -872,43 +776,6 @@ namespace ARMeilleure.Instructions
|
|||||||
context.Copy(GetVec(op.Rd), res);
|
context.Copy(GetVec(op.Rd), res);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Operand EmitShlRegOp(ArmEmitterContext context, Operand op, Operand shiftLsB, int size, bool signed)
|
|
||||||
{
|
|
||||||
Debug.Assert(op.Type == OperandType.I64);
|
|
||||||
Debug.Assert(shiftLsB.Type == OperandType.I32);
|
|
||||||
Debug.Assert((uint)size < 4u);
|
|
||||||
|
|
||||||
Operand negShiftLsB = context.Negate(shiftLsB);
|
|
||||||
|
|
||||||
Operand isInRange = context.BitwiseAnd(
|
|
||||||
context.ICompareLess(shiftLsB, Const(8 << size)),
|
|
||||||
context.ICompareLess(negShiftLsB, Const(8 << size)));
|
|
||||||
|
|
||||||
Operand isPositive = context.ICompareGreaterOrEqual(shiftLsB, Const(0));
|
|
||||||
|
|
||||||
Operand shl = context.ShiftLeft(op, shiftLsB);
|
|
||||||
|
|
||||||
Operand sarOrShr = signed
|
|
||||||
? context.ShiftRightSI(op, negShiftLsB)
|
|
||||||
: context.ShiftRightUI(op, negShiftLsB);
|
|
||||||
|
|
||||||
Operand res = context.ConditionalSelect(isPositive, shl, sarOrShr);
|
|
||||||
|
|
||||||
if (signed)
|
|
||||||
{
|
|
||||||
Operand isPositive2 = context.ICompareGreaterOrEqual(op, Const(0L));
|
|
||||||
|
|
||||||
Operand res2 = context.ConditionalSelect(isPositive2, Const(0L), Const(-1L));
|
|
||||||
res2 = context.ConditionalSelect(isPositive, Const(0L), res2);
|
|
||||||
|
|
||||||
return context.ConditionalSelect(isInRange, res, res2);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return context.ConditionalSelect(isInRange, res, Const(0UL));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void EmitVectorShrImmNarrowOpZx(ArmEmitterContext context, bool round)
|
private static void EmitVectorShrImmNarrowOpZx(ArmEmitterContext context, bool round)
|
||||||
{
|
{
|
||||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||||
@@ -1168,8 +1035,23 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitSshlOrUshl(ArmEmitterContext context, bool signed, bool scalar)
|
[Flags]
|
||||||
|
private enum ShlRegFlags
|
||||||
{
|
{
|
||||||
|
None = 0,
|
||||||
|
Scalar = 1 << 0,
|
||||||
|
Signed = 1 << 1,
|
||||||
|
Round = 1 << 2,
|
||||||
|
Saturating = 1 << 3
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EmitShlRegOp(ArmEmitterContext context, ShlRegFlags flags = ShlRegFlags.None)
|
||||||
|
{
|
||||||
|
bool scalar = flags.HasFlag(ShlRegFlags.Scalar);
|
||||||
|
bool signed = flags.HasFlag(ShlRegFlags.Signed);
|
||||||
|
bool round = flags.HasFlag(ShlRegFlags.Round);
|
||||||
|
bool saturating = flags.HasFlag(ShlRegFlags.Saturating);
|
||||||
|
|
||||||
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
|
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
|
||||||
|
|
||||||
Operand res = context.VectorZero();
|
Operand res = context.VectorZero();
|
||||||
@@ -1178,15 +1060,225 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
for (int index = 0; index < elems; index++)
|
for (int index = 0; index < elems; index++)
|
||||||
{
|
{
|
||||||
Operand ne = EmitVectorExtract (context, op.Rn, index, op.Size, signed);
|
Operand ne = EmitVectorExtract(context, op.Rn, index, op.Size, signed);
|
||||||
Operand me = EmitVectorExtractSx(context, op.Rm, index << op.Size, 0);
|
Operand me = EmitVectorExtractSx(context, op.Rm, index << op.Size, size: 0);
|
||||||
|
|
||||||
Operand e = EmitShlRegOp(context, ne, context.ConvertI64ToI32(me), op.Size, signed);
|
Operand e = !saturating
|
||||||
|
? EmitShlReg(context, ne, context.ConvertI64ToI32(me), round, op.Size, signed)
|
||||||
|
: EmitShlRegSatQ(context, ne, context.ConvertI64ToI32(me), round, op.Size, signed);
|
||||||
|
|
||||||
res = EmitVectorInsert(context, res, e, index, op.Size);
|
res = EmitVectorInsert(context, res, e, index, op.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
context.Copy(GetVec(op.Rd), res);
|
context.Copy(GetVec(op.Rd), res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// long SignedShlReg(long op, int shiftLsB, bool round, int size);
|
||||||
|
// ulong UnsignedShlReg(ulong op, int shiftLsB, bool round, int size);
|
||||||
|
private static Operand EmitShlReg(ArmEmitterContext context, Operand op, Operand shiftLsB, bool round, int size, bool signed)
|
||||||
|
{
|
||||||
|
int eSize = 8 << size;
|
||||||
|
|
||||||
|
Debug.Assert(op.Type == OperandType.I64);
|
||||||
|
Debug.Assert(shiftLsB.Type == OperandType.I32);
|
||||||
|
Debug.Assert(eSize == 8 || eSize == 16 || eSize == 32 || eSize == 64);
|
||||||
|
|
||||||
|
Operand lbl1 = Label();
|
||||||
|
Operand lblEnd = Label();
|
||||||
|
|
||||||
|
Operand eSizeOp = Const(eSize);
|
||||||
|
Operand zero = Const(0);
|
||||||
|
Operand zeroL = Const(0L);
|
||||||
|
|
||||||
|
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op);
|
||||||
|
|
||||||
|
context.BranchIf(lbl1, shiftLsB, zero, Comparison.GreaterOrEqual);
|
||||||
|
context.Copy(res, signed
|
||||||
|
? EmitSignedShrReg(context, op, context.Negate(shiftLsB), round, eSize)
|
||||||
|
: EmitUnsignedShrReg(context, op, context.Negate(shiftLsB), round, eSize));
|
||||||
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
|
context.MarkLabel(lbl1);
|
||||||
|
context.BranchIf(lblEnd, shiftLsB, zero, Comparison.LessOrEqual);
|
||||||
|
Operand shl = context.ShiftLeft(op, shiftLsB);
|
||||||
|
Operand isGreaterOrEqual = context.ICompareGreaterOrEqual(shiftLsB, eSizeOp);
|
||||||
|
context.Copy(res, context.ConditionalSelect(isGreaterOrEqual, zeroL, shl));
|
||||||
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
|
context.MarkLabel(lblEnd);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// long SignedShlRegSatQ(long op, int shiftLsB, bool round, int size);
|
||||||
|
// ulong UnsignedShlRegSatQ(ulong op, int shiftLsB, bool round, int size);
|
||||||
|
private static Operand EmitShlRegSatQ(ArmEmitterContext context, Operand op, Operand shiftLsB, bool round, int size, bool signed)
|
||||||
|
{
|
||||||
|
int eSize = 8 << size;
|
||||||
|
|
||||||
|
Debug.Assert(op.Type == OperandType.I64);
|
||||||
|
Debug.Assert(shiftLsB.Type == OperandType.I32);
|
||||||
|
Debug.Assert(eSize == 8 || eSize == 16 || eSize == 32 || eSize == 64);
|
||||||
|
|
||||||
|
Operand lbl1 = Label();
|
||||||
|
Operand lbl2 = Label();
|
||||||
|
Operand lblEnd = Label();
|
||||||
|
|
||||||
|
Operand eSizeOp = Const(eSize);
|
||||||
|
Operand zero = Const(0);
|
||||||
|
|
||||||
|
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op);
|
||||||
|
|
||||||
|
context.BranchIf(lbl1, shiftLsB, zero, Comparison.GreaterOrEqual);
|
||||||
|
context.Copy(res, signed
|
||||||
|
? EmitSignedShrReg(context, op, context.Negate(shiftLsB), round, eSize)
|
||||||
|
: EmitUnsignedShrReg(context, op, context.Negate(shiftLsB), round, eSize));
|
||||||
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
|
context.MarkLabel(lbl1);
|
||||||
|
context.BranchIf(lblEnd, shiftLsB, zero, Comparison.LessOrEqual);
|
||||||
|
context.BranchIf(lbl2, shiftLsB, eSizeOp, Comparison.Less);
|
||||||
|
context.Copy(res, signed
|
||||||
|
? EmitSignedSignSatQ(context, op, size)
|
||||||
|
: EmitUnsignedSignSatQ(context, op, size));
|
||||||
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
|
context.MarkLabel(lbl2);
|
||||||
|
Operand shl = context.ShiftLeft(op, shiftLsB);
|
||||||
|
if (eSize == 64)
|
||||||
|
{
|
||||||
|
Operand sarOrShr = signed
|
||||||
|
? context.ShiftRightSI(shl, shiftLsB)
|
||||||
|
: context.ShiftRightUI(shl, shiftLsB);
|
||||||
|
context.Copy(res, shl);
|
||||||
|
context.BranchIf(lblEnd, sarOrShr, op, Comparison.Equal);
|
||||||
|
context.Copy(res, signed
|
||||||
|
? EmitSignedSignSatQ(context, op, size)
|
||||||
|
: EmitUnsignedSignSatQ(context, op, size));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.Copy(res, signed
|
||||||
|
? EmitSignedSrcSatQ(context, shl, size, signedDst: true)
|
||||||
|
: EmitUnsignedSrcSatQ(context, shl, size, signedDst: false));
|
||||||
|
}
|
||||||
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
|
context.MarkLabel(lblEnd);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// shift := [1, 128]; eSize := {8, 16, 32, 64}.
|
||||||
|
// long SignedShrReg(long op, int shift, bool round, int eSize);
|
||||||
|
private static Operand EmitSignedShrReg(ArmEmitterContext context, Operand op, Operand shift, bool round, int eSize)
|
||||||
|
{
|
||||||
|
if (round)
|
||||||
|
{
|
||||||
|
Operand lblEnd = Label();
|
||||||
|
|
||||||
|
Operand eSizeOp = Const(eSize);
|
||||||
|
Operand zeroL = Const(0L);
|
||||||
|
Operand one = Const(1);
|
||||||
|
Operand oneL = Const(1L);
|
||||||
|
|
||||||
|
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), zeroL);
|
||||||
|
|
||||||
|
context.BranchIf(lblEnd, shift, eSizeOp, Comparison.GreaterOrEqual);
|
||||||
|
Operand roundConst = context.ShiftLeft(oneL, context.Subtract(shift, one));
|
||||||
|
Operand add = context.Add(op, roundConst);
|
||||||
|
Operand sar = context.ShiftRightSI(add, shift);
|
||||||
|
if (eSize == 64)
|
||||||
|
{
|
||||||
|
Operand shr = context.ShiftRightUI(add, shift);
|
||||||
|
Operand left = context.BitwiseAnd(context.Negate(op), context.BitwiseExclusiveOr(op, add));
|
||||||
|
Operand isLess = context.ICompareLess(left, zeroL);
|
||||||
|
context.Copy(res, context.ConditionalSelect(isLess, shr, sar));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.Copy(res, sar);
|
||||||
|
}
|
||||||
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
|
context.MarkLabel(lblEnd);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Operand lblEnd = Label();
|
||||||
|
|
||||||
|
Operand eSizeOp = Const(eSize);
|
||||||
|
Operand zeroL = Const(0L);
|
||||||
|
Operand negOneL = Const(-1L);
|
||||||
|
|
||||||
|
Operand sar = context.ShiftRightSI(op, shift);
|
||||||
|
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), sar);
|
||||||
|
|
||||||
|
context.BranchIf(lblEnd, shift, eSizeOp, Comparison.Less);
|
||||||
|
Operand isLess = context.ICompareLess(op, zeroL);
|
||||||
|
context.Copy(res, context.ConditionalSelect(isLess, negOneL, zeroL));
|
||||||
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
|
context.MarkLabel(lblEnd);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// shift := [1, 128]; eSize := {8, 16, 32, 64}.
|
||||||
|
// ulong UnsignedShrReg(ulong op, int shift, bool round, int eSize);
|
||||||
|
private static Operand EmitUnsignedShrReg(ArmEmitterContext context, Operand op, Operand shift, bool round, int eSize)
|
||||||
|
{
|
||||||
|
if (round)
|
||||||
|
{
|
||||||
|
Operand lblEnd = Label();
|
||||||
|
|
||||||
|
Operand zeroUL = Const(0UL);
|
||||||
|
Operand one = Const(1);
|
||||||
|
Operand oneUL = Const(1UL);
|
||||||
|
Operand eSizeMaxOp = Const(64);
|
||||||
|
Operand oneShl63UL = Const(1UL << 63);
|
||||||
|
|
||||||
|
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), zeroUL);
|
||||||
|
|
||||||
|
context.BranchIf(lblEnd, shift, eSizeMaxOp, Comparison.Greater);
|
||||||
|
Operand roundConst = context.ShiftLeft(oneUL, context.Subtract(shift, one));
|
||||||
|
Operand add = context.Add(op, roundConst);
|
||||||
|
Operand shr = context.ShiftRightUI(add, shift);
|
||||||
|
Operand isEqual = context.ICompareEqual(shift, eSizeMaxOp);
|
||||||
|
context.Copy(res, context.ConditionalSelect(isEqual, zeroUL, shr));
|
||||||
|
if (eSize == 64)
|
||||||
|
{
|
||||||
|
context.BranchIf(lblEnd, add, op, Comparison.GreaterOrEqualUI);
|
||||||
|
Operand right = context.BitwiseOr(shr, context.ShiftRightUI(oneShl63UL, context.Subtract(shift, one)));
|
||||||
|
context.Copy(res, context.ConditionalSelect(isEqual, oneUL, right));
|
||||||
|
}
|
||||||
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
|
context.MarkLabel(lblEnd);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Operand lblEnd = Label();
|
||||||
|
|
||||||
|
Operand eSizeOp = Const(eSize);
|
||||||
|
Operand zeroUL = Const(0UL);
|
||||||
|
|
||||||
|
Operand shr = context.ShiftRightUI(op, shift);
|
||||||
|
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), shr);
|
||||||
|
|
||||||
|
context.BranchIf(lblEnd, shift, eSizeOp, Comparison.Less);
|
||||||
|
context.Copy(res, zeroUL);
|
||||||
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
|
context.MarkLabel(lblEnd);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -15,11 +15,6 @@ namespace ARMeilleure.Instructions
|
|||||||
private const int DczSizeLog2 = 4; // Log2 size in words
|
private const int DczSizeLog2 = 4; // Log2 size in words
|
||||||
public const int DczSizeInBytes = 4 << DczSizeLog2;
|
public const int DczSizeInBytes = 4 << DczSizeLog2;
|
||||||
|
|
||||||
public static void Hint(ArmEmitterContext context)
|
|
||||||
{
|
|
||||||
// Execute as no-op.
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Isb(ArmEmitterContext context)
|
public static void Isb(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
// Execute as no-op.
|
// Execute as no-op.
|
||||||
|
@@ -45,6 +45,7 @@ namespace ARMeilleure.Instructions
|
|||||||
Dsb,
|
Dsb,
|
||||||
Eon,
|
Eon,
|
||||||
Eor,
|
Eor,
|
||||||
|
Esb,
|
||||||
Extr,
|
Extr,
|
||||||
Hint,
|
Hint,
|
||||||
Isb,
|
Isb,
|
||||||
@@ -81,6 +82,9 @@ namespace ARMeilleure.Instructions
|
|||||||
Sbcs,
|
Sbcs,
|
||||||
Sbfm,
|
Sbfm,
|
||||||
Sdiv,
|
Sdiv,
|
||||||
|
Sel,
|
||||||
|
Sev,
|
||||||
|
Sevl,
|
||||||
Shsub8,
|
Shsub8,
|
||||||
Smaddl,
|
Smaddl,
|
||||||
Smsubl,
|
Smsubl,
|
||||||
@@ -104,12 +108,16 @@ namespace ARMeilleure.Instructions
|
|||||||
Sys,
|
Sys,
|
||||||
Tbnz,
|
Tbnz,
|
||||||
Tbz,
|
Tbz,
|
||||||
|
Tsb,
|
||||||
Ubfm,
|
Ubfm,
|
||||||
Udiv,
|
Udiv,
|
||||||
Umaddl,
|
Umaddl,
|
||||||
Umsubl,
|
Umsubl,
|
||||||
Umulh,
|
Umulh,
|
||||||
Und,
|
Und,
|
||||||
|
Wfe,
|
||||||
|
Wfi,
|
||||||
|
Yield,
|
||||||
|
|
||||||
// FP & SIMD (AArch64)
|
// FP & SIMD (AArch64)
|
||||||
Abs_S,
|
Abs_S,
|
||||||
@@ -519,6 +527,7 @@ namespace ARMeilleure.Instructions
|
|||||||
Revsh,
|
Revsh,
|
||||||
Rsb,
|
Rsb,
|
||||||
Rsc,
|
Rsc,
|
||||||
|
Sadd8,
|
||||||
Sbfx,
|
Sbfx,
|
||||||
Shadd8,
|
Shadd8,
|
||||||
Smla__,
|
Smla__,
|
||||||
@@ -529,6 +538,7 @@ namespace ARMeilleure.Instructions
|
|||||||
Smmls,
|
Smmls,
|
||||||
Smul__,
|
Smul__,
|
||||||
Smmul,
|
Smmul,
|
||||||
|
Ssub8,
|
||||||
Stl,
|
Stl,
|
||||||
Stlb,
|
Stlb,
|
||||||
Stlex,
|
Stlex,
|
||||||
@@ -550,6 +560,7 @@ namespace ARMeilleure.Instructions
|
|||||||
Teq,
|
Teq,
|
||||||
Trap,
|
Trap,
|
||||||
Tst,
|
Tst,
|
||||||
|
Uadd8,
|
||||||
Ubfx,
|
Ubfx,
|
||||||
Uhadd8,
|
Uhadd8,
|
||||||
Uhsub8,
|
Uhsub8,
|
||||||
@@ -558,6 +569,7 @@ namespace ARMeilleure.Instructions
|
|||||||
Umull,
|
Umull,
|
||||||
Usat,
|
Usat,
|
||||||
Usat16,
|
Usat16,
|
||||||
|
Usub8,
|
||||||
Uxtb,
|
Uxtb,
|
||||||
Uxtb16,
|
Uxtb16,
|
||||||
Uxth,
|
Uxth,
|
||||||
@@ -636,6 +648,10 @@ namespace ARMeilleure.Instructions
|
|||||||
Vrev,
|
Vrev,
|
||||||
Vrhadd,
|
Vrhadd,
|
||||||
Vrint,
|
Vrint,
|
||||||
|
Vrinta,
|
||||||
|
Vrintm,
|
||||||
|
Vrintn,
|
||||||
|
Vrintp,
|
||||||
Vrintx,
|
Vrintx,
|
||||||
Vrshr,
|
Vrshr,
|
||||||
Vrshrn,
|
Vrshrn,
|
||||||
|
@@ -5,287 +5,6 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
static class SoftFallback
|
static class SoftFallback
|
||||||
{
|
{
|
||||||
#region "ShlReg"
|
|
||||||
public static long SignedShlReg(long value, long shift, bool round, int size)
|
|
||||||
{
|
|
||||||
int eSize = 8 << size;
|
|
||||||
|
|
||||||
int shiftLsB = (sbyte)shift;
|
|
||||||
|
|
||||||
if (shiftLsB < 0)
|
|
||||||
{
|
|
||||||
return SignedShrReg(value, -shiftLsB, round, eSize);
|
|
||||||
}
|
|
||||||
else if (shiftLsB > 0)
|
|
||||||
{
|
|
||||||
if (shiftLsB >= eSize)
|
|
||||||
{
|
|
||||||
return 0L;
|
|
||||||
}
|
|
||||||
|
|
||||||
return value << shiftLsB;
|
|
||||||
}
|
|
||||||
else /* if (shiftLsB == 0) */
|
|
||||||
{
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ulong UnsignedShlReg(ulong value, ulong shift, bool round, int size)
|
|
||||||
{
|
|
||||||
int eSize = 8 << size;
|
|
||||||
|
|
||||||
int shiftLsB = (sbyte)shift;
|
|
||||||
|
|
||||||
if (shiftLsB < 0)
|
|
||||||
{
|
|
||||||
return UnsignedShrReg(value, -shiftLsB, round, eSize);
|
|
||||||
}
|
|
||||||
else if (shiftLsB > 0)
|
|
||||||
{
|
|
||||||
if (shiftLsB >= eSize)
|
|
||||||
{
|
|
||||||
return 0UL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return value << shiftLsB;
|
|
||||||
}
|
|
||||||
else /* if (shiftLsB == 0) */
|
|
||||||
{
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long SignedShlRegSatQ(long value, long shift, bool round, int size)
|
|
||||||
{
|
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
|
||||||
|
|
||||||
int eSize = 8 << size;
|
|
||||||
|
|
||||||
int shiftLsB = (sbyte)shift;
|
|
||||||
|
|
||||||
if (shiftLsB < 0)
|
|
||||||
{
|
|
||||||
return SignedShrReg(value, -shiftLsB, round, eSize);
|
|
||||||
}
|
|
||||||
else if (shiftLsB > 0)
|
|
||||||
{
|
|
||||||
if (shiftLsB >= eSize)
|
|
||||||
{
|
|
||||||
return SignedSignSatQ(value, eSize, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eSize == 64)
|
|
||||||
{
|
|
||||||
long shl = value << shiftLsB;
|
|
||||||
long shr = shl >> shiftLsB;
|
|
||||||
|
|
||||||
if (shr != value)
|
|
||||||
{
|
|
||||||
return SignedSignSatQ(value, eSize, context);
|
|
||||||
}
|
|
||||||
else /* if (shr == value) */
|
|
||||||
{
|
|
||||||
return shl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else /* if (eSize != 64) */
|
|
||||||
{
|
|
||||||
return SignedSrcSignedDstSatQ(value << shiftLsB, size); // InstEmitSimdHelper.EmitSignedSrcSatQ(signedDst: true).
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else /* if (shiftLsB == 0) */
|
|
||||||
{
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ulong UnsignedShlRegSatQ(ulong value, ulong shift, bool round, int size)
|
|
||||||
{
|
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
|
||||||
|
|
||||||
int eSize = 8 << size;
|
|
||||||
|
|
||||||
int shiftLsB = (sbyte)shift;
|
|
||||||
|
|
||||||
if (shiftLsB < 0)
|
|
||||||
{
|
|
||||||
return UnsignedShrReg(value, -shiftLsB, round, eSize);
|
|
||||||
}
|
|
||||||
else if (shiftLsB > 0)
|
|
||||||
{
|
|
||||||
if (shiftLsB >= eSize)
|
|
||||||
{
|
|
||||||
return UnsignedSignSatQ(value, eSize, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eSize == 64)
|
|
||||||
{
|
|
||||||
ulong shl = value << shiftLsB;
|
|
||||||
ulong shr = shl >> shiftLsB;
|
|
||||||
|
|
||||||
if (shr != value)
|
|
||||||
{
|
|
||||||
return UnsignedSignSatQ(value, eSize, context);
|
|
||||||
}
|
|
||||||
else /* if (shr == value) */
|
|
||||||
{
|
|
||||||
return shl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else /* if (eSize != 64) */
|
|
||||||
{
|
|
||||||
return UnsignedSrcUnsignedDstSatQ(value << shiftLsB, size); // InstEmitSimdHelper.EmitUnsignedSrcSatQ(signedDst: false).
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else /* if (shiftLsB == 0) */
|
|
||||||
{
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static long SignedShrReg(long value, int shift, bool round, int eSize) // shift := [1, 128]; eSize := {8, 16, 32, 64}.
|
|
||||||
{
|
|
||||||
if (round)
|
|
||||||
{
|
|
||||||
if (shift >= eSize)
|
|
||||||
{
|
|
||||||
return 0L;
|
|
||||||
}
|
|
||||||
|
|
||||||
long roundConst = 1L << (shift - 1);
|
|
||||||
|
|
||||||
long add = value + roundConst;
|
|
||||||
|
|
||||||
if (eSize == 64)
|
|
||||||
{
|
|
||||||
if ((~value & (value ^ add)) < 0L)
|
|
||||||
{
|
|
||||||
return (long)((ulong)add >> shift);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return add >> shift;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else /* if (eSize != 64) */
|
|
||||||
{
|
|
||||||
return add >> shift;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else /* if (!round) */
|
|
||||||
{
|
|
||||||
if (shift >= eSize)
|
|
||||||
{
|
|
||||||
if (value < 0L)
|
|
||||||
{
|
|
||||||
return -1L;
|
|
||||||
}
|
|
||||||
else /* if (value >= 0L) */
|
|
||||||
{
|
|
||||||
return 0L;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return value >> shift;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ulong UnsignedShrReg(ulong value, int shift, bool round, int eSize) // shift := [1, 128]; eSize := {8, 16, 32, 64}.
|
|
||||||
{
|
|
||||||
if (round)
|
|
||||||
{
|
|
||||||
if (shift > 64)
|
|
||||||
{
|
|
||||||
return 0UL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ulong roundConst = 1UL << (shift - 1);
|
|
||||||
|
|
||||||
ulong add = value + roundConst;
|
|
||||||
|
|
||||||
if (eSize == 64)
|
|
||||||
{
|
|
||||||
if ((add < value) && (add < roundConst))
|
|
||||||
{
|
|
||||||
if (shift == 64)
|
|
||||||
{
|
|
||||||
return 1UL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (add >> shift) | (0x8000000000000000UL >> (shift - 1));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (shift == 64)
|
|
||||||
{
|
|
||||||
return 0UL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return add >> shift;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else /* if (eSize != 64) */
|
|
||||||
{
|
|
||||||
if (shift == 64)
|
|
||||||
{
|
|
||||||
return 0UL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return add >> shift;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else /* if (!round) */
|
|
||||||
{
|
|
||||||
if (shift >= eSize)
|
|
||||||
{
|
|
||||||
return 0UL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return value >> shift;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static long SignedSignSatQ(long op, int eSize, ExecutionContext context) // eSize := {8, 16, 32, 64}.
|
|
||||||
{
|
|
||||||
long tMaxValue = (1L << (eSize - 1)) - 1L;
|
|
||||||
long tMinValue = -(1L << (eSize - 1));
|
|
||||||
|
|
||||||
if (op > 0L)
|
|
||||||
{
|
|
||||||
context.Fpsr |= FPSR.Qc;
|
|
||||||
|
|
||||||
return tMaxValue;
|
|
||||||
}
|
|
||||||
else if (op < 0L)
|
|
||||||
{
|
|
||||||
context.Fpsr |= FPSR.Qc;
|
|
||||||
|
|
||||||
return tMinValue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return 0L;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ulong UnsignedSignSatQ(ulong op, int eSize, ExecutionContext context) // eSize := {8, 16, 32, 64}.
|
|
||||||
{
|
|
||||||
ulong tMaxValue = ulong.MaxValue >> (64 - eSize);
|
|
||||||
|
|
||||||
if (op > 0UL)
|
|
||||||
{
|
|
||||||
context.Fpsr |= FPSR.Qc;
|
|
||||||
|
|
||||||
return tMaxValue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return 0UL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region "ShrImm64"
|
#region "ShrImm64"
|
||||||
public static long SignedShrImm64(long value, long roundConst, int shift)
|
public static long SignedShrImm64(long value, long roundConst, int shift)
|
||||||
{
|
{
|
||||||
@@ -508,55 +227,6 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "Saturating"
|
|
||||||
private static long SignedSrcSignedDstSatQ(long op, int size)
|
|
||||||
{
|
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
|
||||||
|
|
||||||
int eSize = 8 << size;
|
|
||||||
|
|
||||||
long tMaxValue = (1L << (eSize - 1)) - 1L;
|
|
||||||
long tMinValue = -(1L << (eSize - 1));
|
|
||||||
|
|
||||||
if (op > tMaxValue)
|
|
||||||
{
|
|
||||||
context.Fpsr |= FPSR.Qc;
|
|
||||||
|
|
||||||
return tMaxValue;
|
|
||||||
}
|
|
||||||
else if (op < tMinValue)
|
|
||||||
{
|
|
||||||
context.Fpsr |= FPSR.Qc;
|
|
||||||
|
|
||||||
return tMinValue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return op;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ulong UnsignedSrcUnsignedDstSatQ(ulong op, int size)
|
|
||||||
{
|
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
|
||||||
|
|
||||||
int eSize = 8 << size;
|
|
||||||
|
|
||||||
ulong tMaxValue = (1UL << eSize) - 1UL;
|
|
||||||
|
|
||||||
if (op > tMaxValue)
|
|
||||||
{
|
|
||||||
context.Fpsr |= FPSR.Qc;
|
|
||||||
|
|
||||||
return tMaxValue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return op;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region "Count"
|
#region "Count"
|
||||||
public static ulong CountLeadingSigns(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
|
public static ulong CountLeadingSigns(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
|
||||||
{
|
{
|
||||||
|
@@ -4,6 +4,10 @@ namespace ARMeilleure.State
|
|||||||
{
|
{
|
||||||
TFlag = 5,
|
TFlag = 5,
|
||||||
EFlag = 9,
|
EFlag = 9,
|
||||||
|
GE0Flag = 16,
|
||||||
|
GE1Flag = 17,
|
||||||
|
GE2Flag = 18,
|
||||||
|
GE3Flag = 19,
|
||||||
QFlag = 27,
|
QFlag = 27,
|
||||||
VFlag = 28,
|
VFlag = 28,
|
||||||
CFlag = 29,
|
CFlag = 29,
|
||||||
|
@@ -179,8 +179,6 @@ namespace ARMeilleure.Translation
|
|||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha1SchedulePart2)));
|
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha1SchedulePart2)));
|
||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart1)));
|
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart1)));
|
||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart2)));
|
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart2)));
|
||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShlReg)));
|
|
||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShlRegSatQ)));
|
|
||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShrImm64)));
|
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShrImm64)));
|
||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl1)));
|
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl1)));
|
||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl2)));
|
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl2)));
|
||||||
@@ -190,8 +188,6 @@ namespace ARMeilleure.Translation
|
|||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx2)));
|
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx2)));
|
||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx3)));
|
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx3)));
|
||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx4)));
|
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx4)));
|
||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShlReg)));
|
|
||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShlRegSatQ)));
|
|
||||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShrImm64)));
|
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShrImm64)));
|
||||||
|
|
||||||
SetDelegateInfo(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert)));
|
SetDelegateInfo(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert)));
|
||||||
|
@@ -27,7 +27,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
||||||
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
||||||
|
|
||||||
private const uint InternalVersion = 3683; //! To be incremented manually for each change to the ARMeilleure project.
|
private const uint InternalVersion = 3700; //! To be incremented manually for each change to the ARMeilleure project.
|
||||||
|
|
||||||
private const string ActualDir = "0";
|
private const string ActualDir = "0";
|
||||||
private const string BackupDir = "1";
|
private const string BackupDir = "1";
|
||||||
|
12
README.md
12
README.md
@@ -27,7 +27,7 @@
|
|||||||
</a>
|
</a>
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
<img src="https://raw.githubusercontent.com/Ryujinx/Ryujinx-Website/master/static/public/shell_fullsize.png">
|
<img src="https://raw.githubusercontent.com/Ryujinx/Ryujinx-Website/master/public/assets/images/shell.png">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h5 align="center">
|
<h5 align="center">
|
||||||
@@ -36,8 +36,8 @@
|
|||||||
|
|
||||||
## Compatibility
|
## Compatibility
|
||||||
|
|
||||||
As of January 2022, Ryujinx has been tested on approximately 3,500 titles; over 3,200 boot past menus and into gameplay, with roughly 2,500 of those being considered playable.
|
As of September 2022, Ryujinx has been tested on approximately 3,600 titles; over 3,400 boot past menus and into gameplay, with roughly 2,700 of those being considered playable. You can check out the compatibility list [here](https://github.com/Ryujinx/Ryujinx-Games-List/issues).
|
||||||
You can check out the compatibility list [here](https://github.com/Ryujinx/Ryujinx-Games-List/issues). Anyone is free to submit an updated test on an existing game entry; simply follow the new issue template and testing guidelines, or post as a reply to the applicable game issue. Use the search function to see if a game has been tested already!
|
Anyone is free to submit a new game test or update an existing game test entry; simply follow the new issue template and testing guidelines, or post as a reply to the applicable game issue. Use the search function to see if a game has been tested already!
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
@@ -118,11 +118,11 @@ If you'd like to support the project financially, Ryujinx has an active Patreon
|
|||||||
<img src="https://images.squarespace-cdn.com/content/v1/560c1d39e4b0b4fae0c9cf2a/1567548955044-WVD994WZP76EWF15T0L3/Patreon+Button.png?format=500w" width="150">
|
<img src="https://images.squarespace-cdn.com/content/v1/560c1d39e4b0b4fae0c9cf2a/1567548955044-WVD994WZP76EWF15T0L3/Patreon+Button.png?format=500w" width="150">
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
All the developers working on the project do so on their free time, but the project has several expenses:
|
All developers working on the project do so in their free time, but the project has several expenses:
|
||||||
* Hackable Nintendo Switch consoles to reverse-engineer the hardware
|
* Hackable Nintendo Switch consoles to reverse-engineer the hardware
|
||||||
* Additional computer hardware for testing purposes (e.g. GPUs to diagnose graphical bugs, etc.)
|
* Additional computer hardware for testing purposes (e.g. GPUs to diagnose graphical bugs, etc.)
|
||||||
* Licenses for various software development tools (e.g. Jetbrains, LDN servers, IDA)
|
* Licenses for various software development tools (e.g. Jetbrains, IDA)
|
||||||
* Web hosting and infrastructure maintenance
|
* Web hosting and infrastructure maintenance (e.g. LDN servers)
|
||||||
|
|
||||||
All funds received through Patreon are considered a donation to support the project. Patrons receive early access to progress reports and exclusive access to developer interviews.
|
All funds received through Patreon are considered a donation to support the project. Patrons receive early access to progress reports and exclusive access to developer interviews.
|
||||||
|
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
using ARMeilleure.Translation;
|
using ARMeilleure.Translation;
|
||||||
using ARMeilleure.Translation.PTC;
|
using ARMeilleure.Translation.PTC;
|
||||||
using Avalonia;
|
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using LibHac.Tools.FsSystem;
|
using LibHac.Tools.FsSystem;
|
||||||
@@ -12,10 +11,8 @@ using Ryujinx.Audio.Integration;
|
|||||||
using Ryujinx.Ava.Common;
|
using Ryujinx.Ava.Common;
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Ava.Input;
|
using Ryujinx.Ava.Input;
|
||||||
using Ryujinx.Ava.Ui.Backend.Vulkan;
|
|
||||||
using Ryujinx.Ava.Ui.Controls;
|
using Ryujinx.Ava.Ui.Controls;
|
||||||
using Ryujinx.Ava.Ui.Models;
|
using Ryujinx.Ava.Ui.Models;
|
||||||
using Ryujinx.Ava.Ui.Vulkan;
|
|
||||||
using Ryujinx.Ava.Ui.Windows;
|
using Ryujinx.Ava.Ui.Windows;
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
@@ -39,6 +36,7 @@ using SixLabors.ImageSharp;
|
|||||||
using SixLabors.ImageSharp.Formats.Png;
|
using SixLabors.ImageSharp.Formats.Png;
|
||||||
using SixLabors.ImageSharp.PixelFormats;
|
using SixLabors.ImageSharp.PixelFormats;
|
||||||
using SixLabors.ImageSharp.Processing;
|
using SixLabors.ImageSharp.Processing;
|
||||||
|
using SPB.Graphics.Vulkan;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@@ -58,24 +56,24 @@ namespace Ryujinx.Ava
|
|||||||
{
|
{
|
||||||
private const int CursorHideIdleTime = 8; // Hide Cursor seconds
|
private const int CursorHideIdleTime = 8; // Hide Cursor seconds
|
||||||
private const float MaxResolutionScale = 4.0f; // Max resolution hotkeys can scale to before wrapping.
|
private const float MaxResolutionScale = 4.0f; // Max resolution hotkeys can scale to before wrapping.
|
||||||
|
private const int TargetFps = 60;
|
||||||
|
|
||||||
private static readonly Cursor InvisibleCursor = new Cursor(StandardCursorType.None);
|
private static readonly Cursor InvisibleCursor = new Cursor(StandardCursorType.None);
|
||||||
|
|
||||||
|
private readonly long _ticksPerFrame;
|
||||||
|
private readonly Stopwatch _chrono;
|
||||||
private readonly AccountManager _accountManager;
|
private readonly AccountManager _accountManager;
|
||||||
private readonly UserChannelPersistence _userChannelPersistence;
|
private readonly UserChannelPersistence _userChannelPersistence;
|
||||||
|
|
||||||
private readonly InputManager _inputManager;
|
private readonly InputManager _inputManager;
|
||||||
|
|
||||||
private readonly IKeyboard _keyboardInterface;
|
|
||||||
|
|
||||||
private readonly MainWindow _parent;
|
private readonly MainWindow _parent;
|
||||||
|
private readonly IKeyboard _keyboardInterface;
|
||||||
private readonly GraphicsDebugLevel _glLogLevel;
|
private readonly GraphicsDebugLevel _glLogLevel;
|
||||||
|
|
||||||
private bool _hideCursorOnIdle;
|
private bool _hideCursorOnIdle;
|
||||||
private bool _isStopped;
|
private bool _isStopped;
|
||||||
private bool _isActive;
|
private bool _isActive;
|
||||||
private long _lastCursorMoveTime;
|
private long _lastCursorMoveTime;
|
||||||
|
private long _ticks = 0;
|
||||||
|
|
||||||
private KeyboardHotkeyState _prevHotkeyState;
|
private KeyboardHotkeyState _prevHotkeyState;
|
||||||
|
|
||||||
@@ -93,7 +91,7 @@ namespace Ryujinx.Ava
|
|||||||
public event EventHandler AppExit;
|
public event EventHandler AppExit;
|
||||||
public event EventHandler<StatusUpdatedEventArgs> StatusUpdatedEvent;
|
public event EventHandler<StatusUpdatedEventArgs> StatusUpdatedEvent;
|
||||||
|
|
||||||
public RendererControl Renderer { get; }
|
public RendererHost Renderer { get; }
|
||||||
public VirtualFileSystem VirtualFileSystem { get; }
|
public VirtualFileSystem VirtualFileSystem { get; }
|
||||||
public ContentManager ContentManager { get; }
|
public ContentManager ContentManager { get; }
|
||||||
public Switch Device { get; set; }
|
public Switch Device { get; set; }
|
||||||
@@ -111,7 +109,7 @@ namespace Ryujinx.Ava
|
|||||||
private object _lockObject = new();
|
private object _lockObject = new();
|
||||||
|
|
||||||
public AppHost(
|
public AppHost(
|
||||||
RendererControl renderer,
|
RendererHost renderer,
|
||||||
InputManager inputManager,
|
InputManager inputManager,
|
||||||
string applicationPath,
|
string applicationPath,
|
||||||
VirtualFileSystem virtualFileSystem,
|
VirtualFileSystem virtualFileSystem,
|
||||||
@@ -128,7 +126,7 @@ namespace Ryujinx.Ava
|
|||||||
_hideCursorOnIdle = ConfigurationState.Instance.HideCursorOnIdle;
|
_hideCursorOnIdle = ConfigurationState.Instance.HideCursorOnIdle;
|
||||||
_lastCursorMoveTime = Stopwatch.GetTimestamp();
|
_lastCursorMoveTime = Stopwatch.GetTimestamp();
|
||||||
_glLogLevel = ConfigurationState.Instance.Logger.GraphicsDebugLevel;
|
_glLogLevel = ConfigurationState.Instance.Logger.GraphicsDebugLevel;
|
||||||
_inputManager.SetMouseDriver(new AvaloniaMouseDriver(renderer));
|
_inputManager.SetMouseDriver(new AvaloniaMouseDriver(_parent, renderer));
|
||||||
_keyboardInterface = (IKeyboard)_inputManager.KeyboardDriver.GetGamepad("0");
|
_keyboardInterface = (IKeyboard)_inputManager.KeyboardDriver.GetGamepad("0");
|
||||||
|
|
||||||
NpadManager = _inputManager.CreateNpadManager();
|
NpadManager = _inputManager.CreateNpadManager();
|
||||||
@@ -138,6 +136,9 @@ namespace Ryujinx.Ava
|
|||||||
VirtualFileSystem = virtualFileSystem;
|
VirtualFileSystem = virtualFileSystem;
|
||||||
ContentManager = contentManager;
|
ContentManager = contentManager;
|
||||||
|
|
||||||
|
_chrono = new Stopwatch();
|
||||||
|
_ticksPerFrame = Stopwatch.Frequency / TargetFps;
|
||||||
|
|
||||||
if (ApplicationPath.StartsWith("@SystemContent"))
|
if (ApplicationPath.StartsWith("@SystemContent"))
|
||||||
{
|
{
|
||||||
ApplicationPath = _parent.VirtualFileSystem.SwitchPathToSystemPath(ApplicationPath);
|
ApplicationPath = _parent.VirtualFileSystem.SwitchPathToSystemPath(ApplicationPath);
|
||||||
@@ -177,7 +178,7 @@ namespace Ryujinx.Ava
|
|||||||
if (_renderer != null)
|
if (_renderer != null)
|
||||||
{
|
{
|
||||||
double scale = _parent.PlatformImpl.RenderScaling;
|
double scale = _parent.PlatformImpl.RenderScaling;
|
||||||
_renderer.Window.SetSize((int)(size.Width * scale), (int)(size.Height * scale));
|
_renderer.Window?.SetSize((int)(size.Width * scale), (int)(size.Height * scale));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,8 +336,6 @@ namespace Ryujinx.Ava
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AvaloniaLocator.Current.GetService<VulkanPlatformInterface>()?.MainSurface.Display.ChangeVSyncMode(true);
|
|
||||||
|
|
||||||
_isStopped = true;
|
_isStopped = true;
|
||||||
_isActive = false;
|
_isActive = false;
|
||||||
}
|
}
|
||||||
@@ -376,6 +375,8 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
_gpuCancellationTokenSource.Cancel();
|
_gpuCancellationTokenSource.Cancel();
|
||||||
_gpuCancellationTokenSource.Dispose();
|
_gpuCancellationTokenSource.Dispose();
|
||||||
|
|
||||||
|
_chrono.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DisposeGpu()
|
public void DisposeGpu()
|
||||||
@@ -389,8 +390,7 @@ namespace Ryujinx.Ava
|
|||||||
Renderer?.MakeCurrent();
|
Renderer?.MakeCurrent();
|
||||||
|
|
||||||
Device.DisposeGpu();
|
Device.DisposeGpu();
|
||||||
|
|
||||||
Renderer?.DestroyBackgroundContext();
|
|
||||||
Renderer?.MakeCurrent(null);
|
Renderer?.MakeCurrent(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -596,16 +596,11 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
IRenderer renderer;
|
IRenderer renderer;
|
||||||
|
|
||||||
if (Program.UseVulkan)
|
if (Renderer.IsVulkan)
|
||||||
{
|
{
|
||||||
var vulkan = AvaloniaLocator.Current.GetService<VulkanPlatformInterface>();
|
string preferredGpu = ConfigurationState.Instance.Graphics.PreferredGpu.Value;
|
||||||
|
|
||||||
renderer = new VulkanRenderer(vulkan.Instance.InternalHandle,
|
renderer = new VulkanRenderer(Renderer.CreateVulkanSurface, VulkanHelper.GetRequiredInstanceExtensions, preferredGpu);
|
||||||
vulkan.MainSurface.Device.InternalHandle,
|
|
||||||
vulkan.PhysicalDevice.InternalHandle,
|
|
||||||
vulkan.MainSurface.Device.Queue.InternalHandle,
|
|
||||||
vulkan.PhysicalDevice.QueueFamilyIndex,
|
|
||||||
vulkan.MainSurface.Device.Lock);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -778,11 +773,7 @@ namespace Ryujinx.Ava
|
|||||||
{
|
{
|
||||||
Width = (int)e.Width;
|
Width = (int)e.Width;
|
||||||
Height = (int)e.Height;
|
Height = (int)e.Height;
|
||||||
|
SetRendererWindowSize(e);
|
||||||
if (!Program.UseVulkan)
|
|
||||||
{
|
|
||||||
SetRendererWindowSize(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MainLoop()
|
private void MainLoop()
|
||||||
@@ -822,12 +813,10 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
_renderer.ScreenCaptured += Renderer_ScreenCaptured;
|
_renderer.ScreenCaptured += Renderer_ScreenCaptured;
|
||||||
|
|
||||||
(_renderer as OpenGLRenderer)?.InitializeBackgroundContext(SPBOpenGLContext.CreateBackgroundContext((Renderer as OpenGLRendererControl).GameContext));
|
(_renderer as OpenGLRenderer)?.InitializeBackgroundContext(SPBOpenGLContext.CreateBackgroundContext(Renderer.GetContext()));
|
||||||
|
|
||||||
Renderer.MakeCurrent();
|
Renderer.MakeCurrent();
|
||||||
|
|
||||||
AvaloniaLocator.Current.GetService<VulkanPlatformInterface>()?.MainSurface?.Display?.ChangeVSyncMode(Device.EnableDeviceVsync);
|
|
||||||
|
|
||||||
Device.Gpu.Renderer.Initialize(_glLogLevel);
|
Device.Gpu.Renderer.Initialize(_glLogLevel);
|
||||||
|
|
||||||
Width = (int)Renderer.Bounds.Width;
|
Width = (int)Renderer.Bounds.Width;
|
||||||
@@ -835,16 +824,20 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
_renderer.Window.SetSize((int)(Width * _parent.PlatformImpl.RenderScaling), (int)(Height * _parent.PlatformImpl.RenderScaling));
|
_renderer.Window.SetSize((int)(Width * _parent.PlatformImpl.RenderScaling), (int)(Height * _parent.PlatformImpl.RenderScaling));
|
||||||
|
|
||||||
|
_chrono.Start();
|
||||||
|
|
||||||
Device.Gpu.Renderer.RunLoop(() =>
|
Device.Gpu.Renderer.RunLoop(() =>
|
||||||
{
|
{
|
||||||
Device.Gpu.SetGpuThread();
|
Device.Gpu.SetGpuThread();
|
||||||
Device.Gpu.InitializeShaderCache(_gpuCancellationTokenSource.Token);
|
Device.Gpu.InitializeShaderCache(_gpuCancellationTokenSource.Token);
|
||||||
Translator.IsReadyForTranslation.Set();
|
Translator.IsReadyForTranslation.Set();
|
||||||
|
|
||||||
Renderer.Start();
|
|
||||||
|
|
||||||
while (_isActive)
|
while (_isActive)
|
||||||
{
|
{
|
||||||
|
_ticks += _chrono.ElapsedTicks;
|
||||||
|
|
||||||
|
_chrono.Restart();
|
||||||
|
|
||||||
if (Device.WaitFifo())
|
if (Device.WaitFifo())
|
||||||
{
|
{
|
||||||
Device.Statistics.RecordFifoStart();
|
Device.Statistics.RecordFifoStart();
|
||||||
@@ -860,19 +853,20 @@ namespace Ryujinx.Ava
|
|||||||
_parent.SwitchToGameControl();
|
_parent.SwitchToGameControl();
|
||||||
}
|
}
|
||||||
|
|
||||||
Device.PresentFrame(Present);
|
Device.PresentFrame(() => Renderer?.SwapBuffers());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_ticks >= _ticksPerFrame)
|
||||||
|
{
|
||||||
|
UpdateStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Renderer.Stop();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Renderer?.MakeCurrent(null);
|
Renderer?.MakeCurrent(null);
|
||||||
|
|
||||||
Renderer.SizeChanged -= Window_SizeChanged;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Present(object image)
|
public void UpdateStatus()
|
||||||
{
|
{
|
||||||
// Run a status update only when a frame is to be drawn. This prevents from updating the ui and wasting a render when no frame is queued
|
// Run a status update only when a frame is to be drawn. This prevents from updating the ui and wasting a render when no frame is queued
|
||||||
string dockedMode = ConfigurationState.Instance.System.EnableDockedMode ? LocaleManager.Instance["Docked"] : LocaleManager.Instance["Handheld"];
|
string dockedMode = ConfigurationState.Instance.System.EnableDockedMode ? LocaleManager.Instance["Docked"] : LocaleManager.Instance["Handheld"];
|
||||||
@@ -886,24 +880,12 @@ namespace Ryujinx.Ava
|
|||||||
StatusUpdatedEvent?.Invoke(this, new StatusUpdatedEventArgs(
|
StatusUpdatedEvent?.Invoke(this, new StatusUpdatedEventArgs(
|
||||||
Device.EnableDeviceVsync,
|
Device.EnableDeviceVsync,
|
||||||
Device.GetVolume(),
|
Device.GetVolume(),
|
||||||
Program.UseVulkan ? "Vulkan" : "OpenGL",
|
Renderer.IsVulkan ? "Vulkan" : "OpenGL",
|
||||||
dockedMode,
|
dockedMode,
|
||||||
ConfigurationState.Instance.Graphics.AspectRatio.Value.ToText(),
|
ConfigurationState.Instance.Graphics.AspectRatio.Value.ToText(),
|
||||||
LocaleManager.Instance["Game"] + $": {Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)",
|
LocaleManager.Instance["Game"] + $": {Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)",
|
||||||
$"FIFO: {Device.Statistics.GetFifoPercent():00.00} %",
|
$"FIFO: {Device.Statistics.GetFifoPercent():00.00} %",
|
||||||
$"GPU: {_renderer.GetHardwareInfo().GpuVendor}"));
|
$"GPU: {_renderer.GetHardwareInfo().GpuVendor}"));
|
||||||
|
|
||||||
if (Program.UseVulkan)
|
|
||||||
{
|
|
||||||
var platformInterface = AvaloniaLocator.Current.GetService<VulkanPlatformInterface>();
|
|
||||||
if (platformInterface.MainSurface.Display.IsSurfaceChanged())
|
|
||||||
{
|
|
||||||
SetRendererWindowSize(new Size(Width, Height));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Renderer.Present(image);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ShowExitPrompt()
|
public async Task ShowExitPrompt()
|
||||||
@@ -985,8 +967,6 @@ namespace Ryujinx.Ava
|
|||||||
case KeyboardHotkeyState.ToggleVSync:
|
case KeyboardHotkeyState.ToggleVSync:
|
||||||
Device.EnableDeviceVsync = !Device.EnableDeviceVsync;
|
Device.EnableDeviceVsync = !Device.EnableDeviceVsync;
|
||||||
|
|
||||||
AvaloniaLocator.Current.GetService<VulkanPlatformInterface>()?.MainSurface?.Display?.ChangeVSyncMode(Device.EnableDeviceVsync);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case KeyboardHotkeyState.Screenshot:
|
case KeyboardHotkeyState.Screenshot:
|
||||||
ScreenshotRequested = true;
|
ScreenshotRequested = true;
|
||||||
|
@@ -14,20 +14,27 @@ namespace Ryujinx.Ava.Input
|
|||||||
private Control _widget;
|
private Control _widget;
|
||||||
private bool _isDisposed;
|
private bool _isDisposed;
|
||||||
private Size _size;
|
private Size _size;
|
||||||
|
private readonly Window _window;
|
||||||
|
|
||||||
public bool[] PressedButtons { get; }
|
public bool[] PressedButtons { get; }
|
||||||
|
|
||||||
public Vector2 CurrentPosition { get; private set; }
|
public Vector2 CurrentPosition { get; private set; }
|
||||||
public Vector2 Scroll { get; private set; }
|
public Vector2 Scroll { get; private set; }
|
||||||
|
|
||||||
public AvaloniaMouseDriver(Control parent)
|
public AvaloniaMouseDriver(Window window, Control parent)
|
||||||
{
|
{
|
||||||
_widget = parent;
|
_widget = parent;
|
||||||
|
_window = window;
|
||||||
|
|
||||||
_widget.PointerMoved += Parent_PointerMovedEvent;
|
_widget.PointerMoved += Parent_PointerMovedEvent;
|
||||||
_widget.PointerPressed += Parent_PointerPressEvent;
|
_widget.PointerPressed += Parent_PointerPressEvent;
|
||||||
_widget.PointerReleased += Parent_PointerReleaseEvent;
|
_widget.PointerReleased += Parent_PointerReleaseEvent;
|
||||||
_widget.PointerWheelChanged += Parent_ScrollEvent;
|
_widget.PointerWheelChanged += Parent_ScrollEvent;
|
||||||
|
|
||||||
|
_window.PointerMoved += Parent_PointerMovedEvent;
|
||||||
|
_window.PointerPressed += Parent_PointerPressEvent;
|
||||||
|
_window.PointerReleased += Parent_PointerReleaseEvent;
|
||||||
|
_window.PointerWheelChanged += Parent_ScrollEvent;
|
||||||
|
|
||||||
PressedButtons = new bool[(int)MouseButton.Count];
|
PressedButtons = new bool[(int)MouseButton.Count];
|
||||||
|
|
||||||
@@ -47,7 +54,6 @@ namespace Ryujinx.Ava.Input
|
|||||||
|
|
||||||
private void Parent_PointerReleaseEvent(object o, PointerReleasedEventArgs args)
|
private void Parent_PointerReleaseEvent(object o, PointerReleasedEventArgs args)
|
||||||
{
|
{
|
||||||
var pointerProperties = args.GetCurrentPoint(_widget).Properties;
|
|
||||||
PressedButtons[(int)args.InitialPressMouseButton - 1] = false;
|
PressedButtons[(int)args.InitialPressMouseButton - 1] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,6 +131,11 @@ namespace Ryujinx.Ava.Input
|
|||||||
_widget.PointerReleased -= Parent_PointerReleaseEvent;
|
_widget.PointerReleased -= Parent_PointerReleaseEvent;
|
||||||
_widget.PointerWheelChanged -= Parent_ScrollEvent;
|
_widget.PointerWheelChanged -= Parent_ScrollEvent;
|
||||||
|
|
||||||
|
_window.PointerMoved -= Parent_PointerMovedEvent;
|
||||||
|
_window.PointerPressed -= Parent_PointerPressEvent;
|
||||||
|
_window.PointerReleased -= Parent_PointerReleaseEvent;
|
||||||
|
_window.PointerWheelChanged -= Parent_ScrollEvent;
|
||||||
|
|
||||||
_widget = null;
|
_widget = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,9 +1,7 @@
|
|||||||
using ARMeilleure.Translation.PTC;
|
using ARMeilleure.Translation.PTC;
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.OpenGL;
|
|
||||||
using Avalonia.Rendering;
|
using Avalonia.Rendering;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using Ryujinx.Ava.Ui.Backend;
|
|
||||||
using Ryujinx.Ava.Ui.Controls;
|
using Ryujinx.Ava.Ui.Controls;
|
||||||
using Ryujinx.Ava.Ui.Windows;
|
using Ryujinx.Ava.Ui.Windows;
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
@@ -12,12 +10,10 @@ using Ryujinx.Common.GraphicsDriver;
|
|||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Common.System;
|
using Ryujinx.Common.System;
|
||||||
using Ryujinx.Common.SystemInfo;
|
using Ryujinx.Common.SystemInfo;
|
||||||
using Ryujinx.Graphics.Vulkan;
|
|
||||||
using Ryujinx.Modules;
|
using Ryujinx.Modules;
|
||||||
using Ryujinx.Ui.Common;
|
using Ryujinx.Ui.Common;
|
||||||
using Ryujinx.Ui.Common.Configuration;
|
using Ryujinx.Ui.Common.Configuration;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -34,7 +30,6 @@ namespace Ryujinx.Ava
|
|||||||
public static bool PreviewerDetached { get; private set; }
|
public static bool PreviewerDetached { get; private set; }
|
||||||
|
|
||||||
public static RenderTimer RenderTimer { get; private set; }
|
public static RenderTimer RenderTimer { get; private set; }
|
||||||
public static bool UseVulkan { get; private set; }
|
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
public static extern int MessageBoxA(IntPtr hWnd, string text, string caption, uint type);
|
public static extern int MessageBoxA(IntPtr hWnd, string text, string caption, uint type);
|
||||||
@@ -71,36 +66,16 @@ namespace Ryujinx.Ava
|
|||||||
EnableMultiTouch = true,
|
EnableMultiTouch = true,
|
||||||
EnableIme = true,
|
EnableIme = true,
|
||||||
UseEGL = false,
|
UseEGL = false,
|
||||||
UseGpu = !UseVulkan,
|
UseGpu = false
|
||||||
GlProfiles = new List<GlVersion>()
|
|
||||||
{
|
|
||||||
new GlVersion(GlProfileType.OpenGL, 4, 3)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.With(new Win32PlatformOptions
|
.With(new Win32PlatformOptions
|
||||||
{
|
{
|
||||||
EnableMultitouch = true,
|
EnableMultitouch = true,
|
||||||
UseWgl = !UseVulkan,
|
UseWgl = false,
|
||||||
WglProfiles = new List<GlVersion>()
|
|
||||||
{
|
|
||||||
new GlVersion(GlProfileType.OpenGL, 4, 3)
|
|
||||||
},
|
|
||||||
AllowEglInitialization = false,
|
AllowEglInitialization = false,
|
||||||
CompositionBackdropCornerRadius = 8f,
|
CompositionBackdropCornerRadius = 8f,
|
||||||
})
|
})
|
||||||
.UseSkia()
|
.UseSkia()
|
||||||
.With(new Ui.Vulkan.VulkanOptions()
|
|
||||||
{
|
|
||||||
ApplicationName = "Ryujinx.Graphics.Vulkan",
|
|
||||||
MaxQueueCount = 2,
|
|
||||||
PreferDiscreteGpu = true,
|
|
||||||
PreferredDevice = !PreviewerDetached ? "" : ConfigurationState.Instance.Graphics.PreferredGpu.Value,
|
|
||||||
UseDebug = !PreviewerDetached ? false : ConfigurationState.Instance.Logger.GraphicsDebugLevel.Value != GraphicsDebugLevel.None,
|
|
||||||
})
|
|
||||||
.With(new SkiaOptions()
|
|
||||||
{
|
|
||||||
CustomGpuFactory = UseVulkan ? SkiaGpuFactory.CreateVulkanGpu : null
|
|
||||||
})
|
|
||||||
.AfterSetup(_ =>
|
.AfterSetup(_ =>
|
||||||
{
|
{
|
||||||
AvaloniaLocator.CurrentMutable
|
AvaloniaLocator.CurrentMutable
|
||||||
@@ -176,26 +151,7 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
ReloadConfig();
|
ReloadConfig();
|
||||||
|
|
||||||
UseVulkan = PreviewerDetached ? ConfigurationState.Instance.Graphics.GraphicsBackend.Value == GraphicsBackend.Vulkan : false;
|
ForceDpiAware.Windows();
|
||||||
|
|
||||||
if (UseVulkan)
|
|
||||||
{
|
|
||||||
if (VulkanRenderer.GetPhysicalDevices().Length == 0)
|
|
||||||
{
|
|
||||||
UseVulkan = false;
|
|
||||||
|
|
||||||
ConfigurationState.Instance.Graphics.GraphicsBackend.Value = GraphicsBackend.OpenGl;
|
|
||||||
|
|
||||||
Logger.Warning?.PrintMsg(LogClass.Application, "A suitable Vulkan physical device is not available. Falling back to OpenGL");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (UseVulkan)
|
|
||||||
{
|
|
||||||
// With a custom gpu backend, avalonia doesn't enable dpi awareness, so the backend must handle it. This isn't so for the opengl backed,
|
|
||||||
// as that uses avalonia's gpu backend and it's enabled there.
|
|
||||||
ForceDpiAware.Windows();
|
|
||||||
}
|
|
||||||
|
|
||||||
WindowScaleFactor = ForceDpiAware.GetWindowScaleFactor();
|
WindowScaleFactor = ForceDpiAware.GetWindowScaleFactor();
|
||||||
ActualScaleFactor = ForceDpiAware.GetActualScaleFactor() / BaseDpi;
|
ActualScaleFactor = ForceDpiAware.GetActualScaleFactor() / BaseDpi;
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
@@ -59,29 +60,63 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
|
|
||||||
string input = string.Empty;
|
string input = string.Empty;
|
||||||
|
|
||||||
|
var overlay = new ContentDialogOverlayWindow()
|
||||||
|
{
|
||||||
|
Height = window.Bounds.Height,
|
||||||
|
Width = window.Bounds.Width,
|
||||||
|
Position = window.PointToScreen(new Point())
|
||||||
|
};
|
||||||
|
|
||||||
|
window.PositionChanged += OverlayOnPositionChanged;
|
||||||
|
|
||||||
|
void OverlayOnPositionChanged(object sender, PixelPointEventArgs e)
|
||||||
|
{
|
||||||
|
overlay.Position = window.PointToScreen(new Point());
|
||||||
|
}
|
||||||
|
|
||||||
|
contentDialog = overlay.ContentDialog;
|
||||||
|
|
||||||
|
bool opened = false;
|
||||||
|
|
||||||
content.SetInputLengthValidation(args.StringLengthMin, args.StringLengthMax);
|
content.SetInputLengthValidation(args.StringLengthMin, args.StringLengthMax);
|
||||||
|
|
||||||
if (contentDialog != null)
|
content._host = contentDialog;
|
||||||
|
contentDialog.Title = title;
|
||||||
|
contentDialog.PrimaryButtonText = args.SubmitText;
|
||||||
|
contentDialog.IsPrimaryButtonEnabled = content._checkLength(content.Message.Length);
|
||||||
|
contentDialog.SecondaryButtonText = "";
|
||||||
|
contentDialog.CloseButtonText = LocaleManager.Instance["InputDialogCancel"];
|
||||||
|
contentDialog.Content = content;
|
||||||
|
|
||||||
|
TypedEventHandler<ContentDialog, ContentDialogClosedEventArgs> handler = (sender, eventArgs) =>
|
||||||
{
|
{
|
||||||
content._host = contentDialog;
|
if (eventArgs.Result == ContentDialogResult.Primary)
|
||||||
contentDialog.Title = title;
|
|
||||||
contentDialog.PrimaryButtonText = args.SubmitText;
|
|
||||||
contentDialog.IsPrimaryButtonEnabled = content._checkLength(content.Message.Length);
|
|
||||||
contentDialog.SecondaryButtonText = "";
|
|
||||||
contentDialog.CloseButtonText = LocaleManager.Instance["InputDialogCancel"];
|
|
||||||
contentDialog.Content = content;
|
|
||||||
TypedEventHandler<ContentDialog, ContentDialogClosedEventArgs> handler = (sender, eventArgs) =>
|
|
||||||
{
|
{
|
||||||
if (eventArgs.Result == ContentDialogResult.Primary)
|
result = UserResult.Ok;
|
||||||
{
|
input = content.Input.Text;
|
||||||
result = UserResult.Ok;
|
}
|
||||||
input = content.Input.Text;
|
};
|
||||||
}
|
contentDialog.Closed += handler;
|
||||||
};
|
|
||||||
contentDialog.Closed += handler;
|
overlay.Opened += OverlayOnActivated;
|
||||||
|
|
||||||
|
async void OverlayOnActivated(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (opened)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
opened = true;
|
||||||
|
|
||||||
|
overlay.Position = window.PointToScreen(new Point());
|
||||||
|
|
||||||
await contentDialog.ShowAsync();
|
await contentDialog.ShowAsync();
|
||||||
contentDialog.Closed -= handler;
|
contentDialog.Closed -= handler;
|
||||||
}
|
overlay.Close();
|
||||||
|
};
|
||||||
|
|
||||||
|
await overlay.ShowDialog(window);
|
||||||
|
|
||||||
return (result, input);
|
return (result, input);
|
||||||
}
|
}
|
||||||
|
@@ -1,76 +0,0 @@
|
|||||||
using Avalonia;
|
|
||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using static Ryujinx.Ava.Ui.Backend.Interop;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Backend
|
|
||||||
{
|
|
||||||
public abstract class BackendSurface : IDisposable
|
|
||||||
{
|
|
||||||
protected IntPtr Display => _display;
|
|
||||||
|
|
||||||
private IntPtr _display = IntPtr.Zero;
|
|
||||||
|
|
||||||
[DllImport("libX11.so.6")]
|
|
||||||
public static extern IntPtr XOpenDisplay(IntPtr display);
|
|
||||||
|
|
||||||
[DllImport("libX11.so.6")]
|
|
||||||
public static extern int XCloseDisplay(IntPtr display);
|
|
||||||
|
|
||||||
private PixelSize _currentSize;
|
|
||||||
public IntPtr Handle { get; protected set; }
|
|
||||||
|
|
||||||
public bool IsDisposed { get; private set; }
|
|
||||||
|
|
||||||
public BackendSurface(IntPtr handle)
|
|
||||||
{
|
|
||||||
Handle = handle;
|
|
||||||
|
|
||||||
if (OperatingSystem.IsLinux())
|
|
||||||
{
|
|
||||||
_display = XOpenDisplay(IntPtr.Zero);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public PixelSize Size
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
PixelSize size = new PixelSize();
|
|
||||||
if (OperatingSystem.IsWindows())
|
|
||||||
{
|
|
||||||
GetClientRect(Handle, out var rect);
|
|
||||||
size = new PixelSize(rect.right, rect.bottom);
|
|
||||||
}
|
|
||||||
else if (OperatingSystem.IsLinux())
|
|
||||||
{
|
|
||||||
XWindowAttributes attributes = new XWindowAttributes();
|
|
||||||
XGetWindowAttributes(Display, Handle, ref attributes);
|
|
||||||
|
|
||||||
size = new PixelSize(attributes.width, attributes.height);
|
|
||||||
}
|
|
||||||
|
|
||||||
_currentSize = size;
|
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public PixelSize CurrentSize => _currentSize;
|
|
||||||
|
|
||||||
public virtual void Dispose()
|
|
||||||
{
|
|
||||||
if (IsDisposed)
|
|
||||||
{
|
|
||||||
throw new ObjectDisposedException(nameof(BackendSurface));
|
|
||||||
}
|
|
||||||
|
|
||||||
IsDisposed = true;
|
|
||||||
|
|
||||||
if (_display != IntPtr.Zero)
|
|
||||||
{
|
|
||||||
XCloseDisplay(_display);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,49 +0,0 @@
|
|||||||
using FluentAvalonia.Interop;
|
|
||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Backend
|
|
||||||
{
|
|
||||||
public static class Interop
|
|
||||||
{
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
public struct XWindowAttributes
|
|
||||||
{
|
|
||||||
public int x;
|
|
||||||
public int y;
|
|
||||||
public int width;
|
|
||||||
public int height;
|
|
||||||
public int border_width;
|
|
||||||
public int depth;
|
|
||||||
public IntPtr visual;
|
|
||||||
public IntPtr root;
|
|
||||||
public int c_class;
|
|
||||||
public int bit_gravity;
|
|
||||||
public int win_gravity;
|
|
||||||
public int backing_store;
|
|
||||||
public IntPtr backing_planes;
|
|
||||||
public IntPtr backing_pixel;
|
|
||||||
public int save_under;
|
|
||||||
public IntPtr colormap;
|
|
||||||
public int map_installed;
|
|
||||||
public int map_state;
|
|
||||||
public IntPtr all_event_masks;
|
|
||||||
public IntPtr your_event_mask;
|
|
||||||
public IntPtr do_not_propagate_mask;
|
|
||||||
public int override_direct;
|
|
||||||
public IntPtr screen;
|
|
||||||
}
|
|
||||||
|
|
||||||
[DllImport("user32.dll")]
|
|
||||||
public static extern bool GetClientRect(IntPtr hwnd, out RECT lpRect);
|
|
||||||
|
|
||||||
[DllImport("libX11.so.6")]
|
|
||||||
public static extern int XCloseDisplay(IntPtr display);
|
|
||||||
|
|
||||||
[DllImport("libX11.so.6")]
|
|
||||||
public static extern int XGetWindowAttributes(IntPtr display, IntPtr window, ref XWindowAttributes attributes);
|
|
||||||
|
|
||||||
[DllImport("libX11.so.6")]
|
|
||||||
public static extern IntPtr XOpenDisplay(IntPtr display);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,26 +0,0 @@
|
|||||||
using Avalonia;
|
|
||||||
using Avalonia.Skia;
|
|
||||||
using Ryujinx.Ava.Ui.Vulkan;
|
|
||||||
using Ryujinx.Ava.Ui.Backend.Vulkan;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Backend
|
|
||||||
{
|
|
||||||
public static class SkiaGpuFactory
|
|
||||||
{
|
|
||||||
public static ISkiaGpu CreateVulkanGpu()
|
|
||||||
{
|
|
||||||
var skiaOptions = AvaloniaLocator.Current.GetService<SkiaOptions>() ?? new SkiaOptions();
|
|
||||||
var platformInterface = AvaloniaLocator.Current.GetService<VulkanPlatformInterface>();
|
|
||||||
|
|
||||||
if (platformInterface == null)
|
|
||||||
{
|
|
||||||
VulkanPlatformInterface.TryInitialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
var gpu = new VulkanSkiaGpu(skiaOptions.MaxGpuResourceSizeBytes);
|
|
||||||
AvaloniaLocator.CurrentMutable.Bind<VulkanSkiaGpu>().ToConstant(gpu);
|
|
||||||
|
|
||||||
return gpu;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,17 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Silk.NET.Vulkan;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Vulkan
|
|
||||||
{
|
|
||||||
public static class ResultExtensions
|
|
||||||
{
|
|
||||||
public static void ThrowOnError(this Result result)
|
|
||||||
{
|
|
||||||
// Only negative result codes are errors.
|
|
||||||
if ((int)result < (int)Result.Success)
|
|
||||||
{
|
|
||||||
throw new Exception($"Unexpected API error \"{result}\".");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,201 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Avalonia;
|
|
||||||
using Avalonia.Skia;
|
|
||||||
using Ryujinx.Ava.Ui.Vulkan;
|
|
||||||
using Ryujinx.Ava.Ui.Vulkan.Surfaces;
|
|
||||||
using Silk.NET.Vulkan;
|
|
||||||
using SkiaSharp;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Backend.Vulkan
|
|
||||||
{
|
|
||||||
internal class VulkanRenderTarget : ISkiaGpuRenderTarget
|
|
||||||
{
|
|
||||||
public GRContext GrContext { get; private set; }
|
|
||||||
|
|
||||||
private readonly VulkanSurfaceRenderTarget _surface;
|
|
||||||
private readonly VulkanPlatformInterface _vulkanPlatformInterface;
|
|
||||||
private readonly IVulkanPlatformSurface _vulkanPlatformSurface;
|
|
||||||
private GRVkBackendContext _grVkBackend;
|
|
||||||
|
|
||||||
public VulkanRenderTarget(VulkanPlatformInterface vulkanPlatformInterface, IVulkanPlatformSurface vulkanPlatformSurface)
|
|
||||||
{
|
|
||||||
_surface = vulkanPlatformInterface.CreateRenderTarget(vulkanPlatformSurface);
|
|
||||||
_vulkanPlatformInterface = vulkanPlatformInterface;
|
|
||||||
_vulkanPlatformSurface = vulkanPlatformSurface;
|
|
||||||
|
|
||||||
Initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Initialize()
|
|
||||||
{
|
|
||||||
GRVkGetProcedureAddressDelegate getProc = GetVulkanProcAddress;
|
|
||||||
|
|
||||||
_grVkBackend = new GRVkBackendContext()
|
|
||||||
{
|
|
||||||
VkInstance = _surface.Device.Handle,
|
|
||||||
VkPhysicalDevice = _vulkanPlatformInterface.PhysicalDevice.Handle,
|
|
||||||
VkDevice = _surface.Device.Handle,
|
|
||||||
VkQueue = _surface.Device.Queue.Handle,
|
|
||||||
GraphicsQueueIndex = _vulkanPlatformInterface.PhysicalDevice.QueueFamilyIndex,
|
|
||||||
GetProcedureAddress = getProc
|
|
||||||
};
|
|
||||||
|
|
||||||
GrContext = GRContext.CreateVulkan(_grVkBackend);
|
|
||||||
|
|
||||||
var gpu = AvaloniaLocator.Current.GetService<VulkanSkiaGpu>();
|
|
||||||
|
|
||||||
if (gpu.MaxResourceBytes.HasValue)
|
|
||||||
{
|
|
||||||
GrContext.SetResourceCacheLimit(gpu.MaxResourceBytes.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private IntPtr GetVulkanProcAddress(string name, IntPtr instanceHandle, IntPtr deviceHandle)
|
|
||||||
{
|
|
||||||
IntPtr addr;
|
|
||||||
|
|
||||||
if (deviceHandle != IntPtr.Zero)
|
|
||||||
{
|
|
||||||
addr = _vulkanPlatformInterface.Api.GetDeviceProcAddr(new Device(deviceHandle), name);
|
|
||||||
|
|
||||||
if (addr != IntPtr.Zero)
|
|
||||||
{
|
|
||||||
return addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
addr = _vulkanPlatformInterface.Api.GetDeviceProcAddr(new Device(_surface.Device.Handle), name);
|
|
||||||
|
|
||||||
if (addr != IntPtr.Zero)
|
|
||||||
{
|
|
||||||
return addr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
addr = _vulkanPlatformInterface.Api.GetInstanceProcAddr(new Instance(_vulkanPlatformInterface.Instance.Handle), name);
|
|
||||||
|
|
||||||
if (addr == IntPtr.Zero)
|
|
||||||
{
|
|
||||||
addr = _vulkanPlatformInterface.Api.GetInstanceProcAddr(new Instance(instanceHandle), name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_grVkBackend.Dispose();
|
|
||||||
GrContext.Dispose();
|
|
||||||
_surface.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ISkiaGpuRenderSession BeginRenderingSession()
|
|
||||||
{
|
|
||||||
var session = _surface.BeginDraw(_vulkanPlatformSurface.Scaling);
|
|
||||||
bool success = false;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var disp = session.Display;
|
|
||||||
var api = session.Api;
|
|
||||||
|
|
||||||
var size = session.Size;
|
|
||||||
var scaling = session.Scaling;
|
|
||||||
if (size.Width <= 0 || size.Height <= 0 || scaling < 0)
|
|
||||||
{
|
|
||||||
size = new Avalonia.PixelSize(1, 1);
|
|
||||||
scaling = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
lock (GrContext)
|
|
||||||
{
|
|
||||||
GrContext.ResetContext();
|
|
||||||
|
|
||||||
var image = _surface.GetImage();
|
|
||||||
|
|
||||||
var imageInfo = new GRVkImageInfo()
|
|
||||||
{
|
|
||||||
CurrentQueueFamily = disp.QueueFamilyIndex,
|
|
||||||
Format = (uint)image.Format,
|
|
||||||
Image = image.Handle,
|
|
||||||
ImageLayout = (uint)image.CurrentLayout,
|
|
||||||
ImageTiling = (uint)image.Tiling,
|
|
||||||
ImageUsageFlags = _surface.UsageFlags,
|
|
||||||
LevelCount = _surface.MipLevels,
|
|
||||||
SampleCount = 1,
|
|
||||||
Protected = false,
|
|
||||||
Alloc = new GRVkAlloc()
|
|
||||||
{
|
|
||||||
Memory = image.MemoryHandle,
|
|
||||||
Flags = 0,
|
|
||||||
Offset = 0,
|
|
||||||
Size = _surface.MemorySize
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var renderTarget =
|
|
||||||
new GRBackendRenderTarget((int)size.Width, (int)size.Height, 1,
|
|
||||||
imageInfo);
|
|
||||||
var surface = SKSurface.Create(GrContext, renderTarget,
|
|
||||||
GRSurfaceOrigin.TopLeft,
|
|
||||||
_surface.IsRgba ? SKColorType.Rgba8888 : SKColorType.Bgra8888, SKColorSpace.CreateSrgb());
|
|
||||||
|
|
||||||
if (surface == null)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException(
|
|
||||||
"Surface can't be created with the provided render target");
|
|
||||||
}
|
|
||||||
|
|
||||||
success = true;
|
|
||||||
|
|
||||||
return new VulkanGpuSession(GrContext, renderTarget, surface, session);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (!success)
|
|
||||||
{
|
|
||||||
session.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsCorrupted { get; }
|
|
||||||
|
|
||||||
internal class VulkanGpuSession : ISkiaGpuRenderSession
|
|
||||||
{
|
|
||||||
private readonly GRBackendRenderTarget _backendRenderTarget;
|
|
||||||
private readonly VulkanSurfaceRenderingSession _vulkanSession;
|
|
||||||
|
|
||||||
public VulkanGpuSession(GRContext grContext,
|
|
||||||
GRBackendRenderTarget backendRenderTarget,
|
|
||||||
SKSurface surface,
|
|
||||||
VulkanSurfaceRenderingSession vulkanSession)
|
|
||||||
{
|
|
||||||
GrContext = grContext;
|
|
||||||
_backendRenderTarget = backendRenderTarget;
|
|
||||||
SkSurface = surface;
|
|
||||||
_vulkanSession = vulkanSession;
|
|
||||||
|
|
||||||
SurfaceOrigin = GRSurfaceOrigin.TopLeft;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
lock (_vulkanSession.Display.Lock)
|
|
||||||
{
|
|
||||||
SkSurface.Canvas.Flush();
|
|
||||||
|
|
||||||
SkSurface.Dispose();
|
|
||||||
_backendRenderTarget.Dispose();
|
|
||||||
GrContext.Flush();
|
|
||||||
|
|
||||||
_vulkanSession.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public GRContext GrContext { get; }
|
|
||||||
public SKSurface SkSurface { get; }
|
|
||||||
public double ScaleFactor => _vulkanSession.Scaling;
|
|
||||||
public GRSurfaceOrigin SurfaceOrigin { get; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,61 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Avalonia;
|
|
||||||
using Avalonia.Platform;
|
|
||||||
using Avalonia.Skia;
|
|
||||||
using Avalonia.X11;
|
|
||||||
using Ryujinx.Ava.Ui.Vulkan;
|
|
||||||
using Silk.NET.Vulkan;
|
|
||||||
using SkiaSharp;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Backend.Vulkan
|
|
||||||
{
|
|
||||||
public class VulkanSkiaGpu : ISkiaGpu
|
|
||||||
{
|
|
||||||
private readonly VulkanPlatformInterface _vulkan;
|
|
||||||
public long? MaxResourceBytes { get; }
|
|
||||||
|
|
||||||
public VulkanSkiaGpu(long? maxResourceBytes)
|
|
||||||
{
|
|
||||||
_vulkan = AvaloniaLocator.Current.GetService<VulkanPlatformInterface>();
|
|
||||||
MaxResourceBytes = maxResourceBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ISkiaGpuRenderTarget TryCreateRenderTarget(IEnumerable<object> surfaces)
|
|
||||||
{
|
|
||||||
foreach (var surface in surfaces)
|
|
||||||
{
|
|
||||||
VulkanWindowSurface window;
|
|
||||||
|
|
||||||
if (surface is IPlatformHandle handle)
|
|
||||||
{
|
|
||||||
window = new VulkanWindowSurface(handle.Handle);
|
|
||||||
}
|
|
||||||
else if (surface is X11FramebufferSurface x11FramebufferSurface)
|
|
||||||
{
|
|
||||||
// As of Avalonia 0.10.13, an IPlatformHandle isn't passed for linux, so use reflection to otherwise get the window id
|
|
||||||
var xId = (IntPtr)x11FramebufferSurface.GetType().GetField(
|
|
||||||
"_xid",
|
|
||||||
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(x11FramebufferSurface);
|
|
||||||
|
|
||||||
window = new VulkanWindowSurface(xId);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
VulkanRenderTarget vulkanRenderTarget = new VulkanRenderTarget(_vulkan, window);
|
|
||||||
|
|
||||||
return vulkanRenderTarget;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ISkiaSurface TryCreateSurface(PixelSize size, ISkiaGpuRenderSession session)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,53 +0,0 @@
|
|||||||
using Avalonia;
|
|
||||||
using Ryujinx.Ava.Ui.Vulkan;
|
|
||||||
using Ryujinx.Ava.Ui.Vulkan.Surfaces;
|
|
||||||
using Silk.NET.Vulkan;
|
|
||||||
using Silk.NET.Vulkan.Extensions.KHR;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Backend.Vulkan
|
|
||||||
{
|
|
||||||
internal class VulkanWindowSurface : BackendSurface, IVulkanPlatformSurface
|
|
||||||
{
|
|
||||||
public float Scaling => (float)Program.ActualScaleFactor;
|
|
||||||
|
|
||||||
public PixelSize SurfaceSize => Size;
|
|
||||||
|
|
||||||
public VulkanWindowSurface(IntPtr handle) : base(handle)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public unsafe SurfaceKHR CreateSurface(VulkanInstance instance)
|
|
||||||
{
|
|
||||||
if (OperatingSystem.IsWindows())
|
|
||||||
{
|
|
||||||
if (instance.Api.TryGetInstanceExtension(new Instance(instance.Handle), out KhrWin32Surface surfaceExtension))
|
|
||||||
{
|
|
||||||
var createInfo = new Win32SurfaceCreateInfoKHR() { Hinstance = 0, Hwnd = Handle, SType = StructureType.Win32SurfaceCreateInfoKhr };
|
|
||||||
|
|
||||||
surfaceExtension.CreateWin32Surface(new Instance(instance.Handle), createInfo, null, out var surface).ThrowOnError();
|
|
||||||
|
|
||||||
return surface;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (OperatingSystem.IsLinux())
|
|
||||||
{
|
|
||||||
if (instance.Api.TryGetInstanceExtension(new Instance(instance.Handle), out KhrXlibSurface surfaceExtension))
|
|
||||||
{
|
|
||||||
var createInfo = new XlibSurfaceCreateInfoKHR()
|
|
||||||
{
|
|
||||||
SType = StructureType.XlibSurfaceCreateInfoKhr,
|
|
||||||
Dpy = (nint*)Display,
|
|
||||||
Window = Handle
|
|
||||||
};
|
|
||||||
|
|
||||||
surfaceExtension.CreateXlibSurface(new Instance(instance.Handle), createInfo, null, out var surface).ThrowOnError();
|
|
||||||
|
|
||||||
return surface;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new PlatformNotSupportedException("The current platform does not support surface creation.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,13 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Avalonia;
|
|
||||||
using Silk.NET.Vulkan;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Vulkan.Surfaces
|
|
||||||
{
|
|
||||||
public interface IVulkanPlatformSurface : IDisposable
|
|
||||||
{
|
|
||||||
float Scaling { get; }
|
|
||||||
PixelSize SurfaceSize { get; }
|
|
||||||
SurfaceKHR CreateSurface(VulkanInstance instance);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,134 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Avalonia;
|
|
||||||
using Ryujinx.Graphics.Vulkan;
|
|
||||||
using Silk.NET.Vulkan;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Vulkan.Surfaces
|
|
||||||
{
|
|
||||||
internal class VulkanSurfaceRenderTarget : IDisposable
|
|
||||||
{
|
|
||||||
private readonly VulkanPlatformInterface _platformInterface;
|
|
||||||
private readonly Format _format;
|
|
||||||
|
|
||||||
private VulkanCommandBufferPool.VulkanCommandBuffer _commandBuffer;
|
|
||||||
private VulkanImage Image { get; set; }
|
|
||||||
private object _lock = new object();
|
|
||||||
|
|
||||||
public uint MipLevels => Image.MipLevels;
|
|
||||||
public VulkanDevice Device { get; }
|
|
||||||
|
|
||||||
public VulkanSurfaceRenderTarget(VulkanPlatformInterface platformInterface, VulkanSurface surface)
|
|
||||||
{
|
|
||||||
_platformInterface = platformInterface;
|
|
||||||
|
|
||||||
var device = VulkanInitialization.CreateDevice(platformInterface.Api,
|
|
||||||
platformInterface.PhysicalDevice.InternalHandle,
|
|
||||||
platformInterface.PhysicalDevice.QueueFamilyIndex,
|
|
||||||
VulkanInitialization.GetSupportedExtensions(platformInterface.Api, platformInterface.PhysicalDevice.InternalHandle),
|
|
||||||
platformInterface.PhysicalDevice.QueueCount);
|
|
||||||
|
|
||||||
Device = new VulkanDevice(device, platformInterface.PhysicalDevice, platformInterface.Api);
|
|
||||||
|
|
||||||
Display = VulkanDisplay.CreateDisplay(
|
|
||||||
platformInterface.Instance,
|
|
||||||
Device,
|
|
||||||
platformInterface.PhysicalDevice,
|
|
||||||
surface);
|
|
||||||
Surface = surface;
|
|
||||||
|
|
||||||
// Skia seems to only create surfaces from images with unorm format
|
|
||||||
IsRgba = Display.SurfaceFormat.Format >= Format.R8G8B8A8Unorm &&
|
|
||||||
Display.SurfaceFormat.Format <= Format.R8G8B8A8Srgb;
|
|
||||||
|
|
||||||
_format = IsRgba ? Format.R8G8B8A8Unorm : Format.B8G8R8A8Unorm;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsRgba { get; }
|
|
||||||
|
|
||||||
public uint ImageFormat => (uint)_format;
|
|
||||||
|
|
||||||
public ulong MemorySize => Image.MemorySize;
|
|
||||||
|
|
||||||
public VulkanDisplay Display { get; private set; }
|
|
||||||
|
|
||||||
public VulkanSurface Surface { get; private set; }
|
|
||||||
|
|
||||||
public uint UsageFlags => Image.UsageFlags;
|
|
||||||
|
|
||||||
public PixelSize Size { get; private set; }
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
DestroyImage();
|
|
||||||
Display?.Dispose();
|
|
||||||
Surface?.Dispose();
|
|
||||||
Device?.Dispose();
|
|
||||||
|
|
||||||
Display = null;
|
|
||||||
Surface = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public VulkanSurfaceRenderingSession BeginDraw(float scaling)
|
|
||||||
{
|
|
||||||
if (Image == null)
|
|
||||||
{
|
|
||||||
RecreateImage();
|
|
||||||
}
|
|
||||||
|
|
||||||
_commandBuffer?.WaitForFence();
|
|
||||||
_commandBuffer = null;
|
|
||||||
|
|
||||||
var session = new VulkanSurfaceRenderingSession(Display, Device, this, scaling);
|
|
||||||
|
|
||||||
Image.TransitionLayout(ImageLayout.ColorAttachmentOptimal, AccessFlags.AccessNoneKhr);
|
|
||||||
|
|
||||||
return session;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RecreateImage()
|
|
||||||
{
|
|
||||||
DestroyImage();
|
|
||||||
CreateImage();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CreateImage()
|
|
||||||
{
|
|
||||||
Size = Display.Size;
|
|
||||||
|
|
||||||
Image = new VulkanImage(Device, _platformInterface.PhysicalDevice, Display.CommandBufferPool, ImageFormat, Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DestroyImage()
|
|
||||||
{
|
|
||||||
_commandBuffer?.WaitForFence();
|
|
||||||
_commandBuffer = null;
|
|
||||||
Image?.Dispose();
|
|
||||||
Image = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public VulkanImage GetImage()
|
|
||||||
{
|
|
||||||
return Image;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void EndDraw()
|
|
||||||
{
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
if (Display == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_commandBuffer = Display.StartPresentation();
|
|
||||||
|
|
||||||
Display.BlitImageToCurrentImage(this, _commandBuffer.InternalHandle);
|
|
||||||
|
|
||||||
Display.EndPresentation(_commandBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,215 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Silk.NET.Vulkan;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Vulkan
|
|
||||||
{
|
|
||||||
internal class VulkanCommandBufferPool : IDisposable
|
|
||||||
{
|
|
||||||
private readonly VulkanDevice _device;
|
|
||||||
private readonly CommandPool _commandPool;
|
|
||||||
|
|
||||||
private readonly List<VulkanCommandBuffer> _usedCommandBuffers = new();
|
|
||||||
private readonly object _lock = new object();
|
|
||||||
|
|
||||||
public unsafe VulkanCommandBufferPool(VulkanDevice device, VulkanPhysicalDevice physicalDevice)
|
|
||||||
{
|
|
||||||
_device = device;
|
|
||||||
|
|
||||||
var commandPoolCreateInfo = new CommandPoolCreateInfo
|
|
||||||
{
|
|
||||||
SType = StructureType.CommandPoolCreateInfo,
|
|
||||||
Flags = CommandPoolCreateFlags.CommandPoolCreateResetCommandBufferBit,
|
|
||||||
QueueFamilyIndex = physicalDevice.QueueFamilyIndex
|
|
||||||
};
|
|
||||||
|
|
||||||
device.Api.CreateCommandPool(_device.InternalHandle, commandPoolCreateInfo, null, out _commandPool)
|
|
||||||
.ThrowOnError();
|
|
||||||
}
|
|
||||||
|
|
||||||
private CommandBuffer AllocateCommandBuffer()
|
|
||||||
{
|
|
||||||
var commandBufferAllocateInfo = new CommandBufferAllocateInfo
|
|
||||||
{
|
|
||||||
SType = StructureType.CommandBufferAllocateInfo,
|
|
||||||
CommandPool = _commandPool,
|
|
||||||
CommandBufferCount = 1,
|
|
||||||
Level = CommandBufferLevel.Primary
|
|
||||||
};
|
|
||||||
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
_device.Api.AllocateCommandBuffers(_device.InternalHandle, commandBufferAllocateInfo, out var commandBuffer);
|
|
||||||
|
|
||||||
return commandBuffer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public VulkanCommandBuffer CreateCommandBuffer()
|
|
||||||
{
|
|
||||||
return new(_device, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void FreeUsedCommandBuffers()
|
|
||||||
{
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
foreach (var usedCommandBuffer in _usedCommandBuffers)
|
|
||||||
{
|
|
||||||
usedCommandBuffer.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
_usedCommandBuffers.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DisposeCommandBuffer(VulkanCommandBuffer commandBuffer)
|
|
||||||
{
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
_usedCommandBuffers.Add(commandBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
FreeUsedCommandBuffers();
|
|
||||||
_device.Api.DestroyCommandPool(_device.InternalHandle, _commandPool, Span<AllocationCallbacks>.Empty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class VulkanCommandBuffer : IDisposable
|
|
||||||
{
|
|
||||||
private readonly VulkanCommandBufferPool _commandBufferPool;
|
|
||||||
private readonly VulkanDevice _device;
|
|
||||||
private readonly Fence _fence;
|
|
||||||
private bool _hasEnded;
|
|
||||||
private bool _hasStarted;
|
|
||||||
private bool _isDisposed;
|
|
||||||
private object _lock = new object();
|
|
||||||
|
|
||||||
public IntPtr Handle => InternalHandle.Handle;
|
|
||||||
|
|
||||||
internal CommandBuffer InternalHandle { get; }
|
|
||||||
|
|
||||||
internal unsafe VulkanCommandBuffer(VulkanDevice device, VulkanCommandBufferPool commandBufferPool)
|
|
||||||
{
|
|
||||||
_device = device;
|
|
||||||
_commandBufferPool = commandBufferPool;
|
|
||||||
|
|
||||||
InternalHandle = _commandBufferPool.AllocateCommandBuffer();
|
|
||||||
|
|
||||||
var fenceCreateInfo = new FenceCreateInfo()
|
|
||||||
{
|
|
||||||
SType = StructureType.FenceCreateInfo,
|
|
||||||
Flags = FenceCreateFlags.FenceCreateSignaledBit
|
|
||||||
};
|
|
||||||
|
|
||||||
device.Api.CreateFence(device.InternalHandle, fenceCreateInfo, null, out _fence);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WaitForFence()
|
|
||||||
{
|
|
||||||
if (_isDisposed)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
if (!_isDisposed)
|
|
||||||
{
|
|
||||||
_device.Api.WaitForFences(_device.InternalHandle, 1, _fence, true, ulong.MaxValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void BeginRecording()
|
|
||||||
{
|
|
||||||
if (!_hasStarted)
|
|
||||||
{
|
|
||||||
_hasStarted = true;
|
|
||||||
|
|
||||||
var beginInfo = new CommandBufferBeginInfo
|
|
||||||
{
|
|
||||||
SType = StructureType.CommandBufferBeginInfo,
|
|
||||||
Flags = CommandBufferUsageFlags.CommandBufferUsageOneTimeSubmitBit
|
|
||||||
};
|
|
||||||
|
|
||||||
_device.Api.BeginCommandBuffer(InternalHandle, beginInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void EndRecording()
|
|
||||||
{
|
|
||||||
if (_hasStarted && !_hasEnded)
|
|
||||||
{
|
|
||||||
_hasEnded = true;
|
|
||||||
|
|
||||||
_device.Api.EndCommandBuffer(InternalHandle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Submit()
|
|
||||||
{
|
|
||||||
Submit(null, null, null, _fence);
|
|
||||||
}
|
|
||||||
|
|
||||||
public unsafe void Submit(
|
|
||||||
ReadOnlySpan<Semaphore> waitSemaphores,
|
|
||||||
ReadOnlySpan<PipelineStageFlags> waitDstStageMask,
|
|
||||||
ReadOnlySpan<Semaphore> signalSemaphores,
|
|
||||||
Fence? fence = null)
|
|
||||||
{
|
|
||||||
EndRecording();
|
|
||||||
|
|
||||||
if (!fence.HasValue)
|
|
||||||
{
|
|
||||||
fence = _fence;
|
|
||||||
}
|
|
||||||
|
|
||||||
fixed (Semaphore* pWaitSemaphores = waitSemaphores, pSignalSemaphores = signalSemaphores)
|
|
||||||
{
|
|
||||||
fixed (PipelineStageFlags* pWaitDstStageMask = waitDstStageMask)
|
|
||||||
{
|
|
||||||
var commandBuffer = InternalHandle;
|
|
||||||
var submitInfo = new SubmitInfo
|
|
||||||
{
|
|
||||||
SType = StructureType.SubmitInfo,
|
|
||||||
WaitSemaphoreCount = waitSemaphores != null ? (uint)waitSemaphores.Length : 0,
|
|
||||||
PWaitSemaphores = pWaitSemaphores,
|
|
||||||
PWaitDstStageMask = pWaitDstStageMask,
|
|
||||||
CommandBufferCount = 1,
|
|
||||||
PCommandBuffers = &commandBuffer,
|
|
||||||
SignalSemaphoreCount = signalSemaphores != null ? (uint)signalSemaphores.Length : 0,
|
|
||||||
PSignalSemaphores = pSignalSemaphores,
|
|
||||||
};
|
|
||||||
|
|
||||||
_device.Api.ResetFences(_device.InternalHandle, 1, fence.Value);
|
|
||||||
|
|
||||||
_device.Submit(submitInfo, fence.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_commandBufferPool.DisposeCommandBuffer(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
if (!_isDisposed)
|
|
||||||
{
|
|
||||||
_isDisposed = true;
|
|
||||||
|
|
||||||
_device.Api.WaitForFences(_device.InternalHandle, 1, _fence, true, ulong.MaxValue);
|
|
||||||
_device.Api.FreeCommandBuffers(_device.InternalHandle, _commandBufferPool._commandPool, 1, InternalHandle);
|
|
||||||
_device.Api.DestroyFence(_device.InternalHandle, _fence, Span<AllocationCallbacks>.Empty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,63 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Silk.NET.Vulkan;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Vulkan
|
|
||||||
{
|
|
||||||
internal class VulkanDevice : IDisposable
|
|
||||||
{
|
|
||||||
private static object _lock = new object();
|
|
||||||
|
|
||||||
public VulkanDevice(Device apiHandle, VulkanPhysicalDevice physicalDevice, Vk api)
|
|
||||||
{
|
|
||||||
InternalHandle = apiHandle;
|
|
||||||
Api = api;
|
|
||||||
|
|
||||||
api.GetDeviceQueue(apiHandle, physicalDevice.QueueFamilyIndex, 0, out var queue);
|
|
||||||
|
|
||||||
Queue = new VulkanQueue(this, queue);
|
|
||||||
|
|
||||||
PresentQueue = Queue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IntPtr Handle => InternalHandle.Handle;
|
|
||||||
|
|
||||||
internal Device InternalHandle { get; }
|
|
||||||
public Vk Api { get; }
|
|
||||||
|
|
||||||
public VulkanQueue Queue { get; private set; }
|
|
||||||
public VulkanQueue PresentQueue { get; }
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
WaitIdle();
|
|
||||||
Queue = null;
|
|
||||||
Api.DestroyDevice(InternalHandle, Span<AllocationCallbacks>.Empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void Submit(SubmitInfo submitInfo, Fence fence = default)
|
|
||||||
{
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
Api.QueueSubmit(Queue.InternalHandle, 1, submitInfo, fence).ThrowOnError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WaitIdle()
|
|
||||||
{
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
Api.DeviceWaitIdle(InternalHandle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void QueueWaitIdle()
|
|
||||||
{
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
Api.QueueWaitIdle(Queue.InternalHandle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public object Lock => _lock;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,456 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using Avalonia;
|
|
||||||
using Ryujinx.Ava.Ui.Vulkan.Surfaces;
|
|
||||||
using Silk.NET.Vulkan;
|
|
||||||
using Silk.NET.Vulkan.Extensions.KHR;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Vulkan
|
|
||||||
{
|
|
||||||
internal class VulkanDisplay : IDisposable
|
|
||||||
{
|
|
||||||
private static KhrSwapchain _swapchainExtension;
|
|
||||||
private readonly VulkanInstance _instance;
|
|
||||||
private readonly VulkanPhysicalDevice _physicalDevice;
|
|
||||||
private readonly VulkanSemaphorePair _semaphorePair;
|
|
||||||
private readonly VulkanDevice _device;
|
|
||||||
private uint _nextImage;
|
|
||||||
private readonly VulkanSurface _surface;
|
|
||||||
private SurfaceFormatKHR _surfaceFormat;
|
|
||||||
private SwapchainKHR _swapchain;
|
|
||||||
private Extent2D _swapchainExtent;
|
|
||||||
private Image[] _swapchainImages;
|
|
||||||
private ImageView[] _swapchainImageViews = Array.Empty<ImageView>();
|
|
||||||
private bool _vsyncStateChanged;
|
|
||||||
private bool _vsyncEnabled;
|
|
||||||
private bool _surfaceChanged;
|
|
||||||
|
|
||||||
public event EventHandler Presented;
|
|
||||||
|
|
||||||
public VulkanCommandBufferPool CommandBufferPool { get; set; }
|
|
||||||
|
|
||||||
public object Lock => _device.Lock;
|
|
||||||
|
|
||||||
private VulkanDisplay(VulkanInstance instance, VulkanDevice device,
|
|
||||||
VulkanPhysicalDevice physicalDevice, VulkanSurface surface, SwapchainKHR swapchain,
|
|
||||||
Extent2D swapchainExtent)
|
|
||||||
{
|
|
||||||
_instance = instance;
|
|
||||||
_device = device;
|
|
||||||
_physicalDevice = physicalDevice;
|
|
||||||
_swapchain = swapchain;
|
|
||||||
_swapchainExtent = swapchainExtent;
|
|
||||||
_surface = surface;
|
|
||||||
|
|
||||||
CreateSwapchainImages();
|
|
||||||
|
|
||||||
_semaphorePair = new VulkanSemaphorePair(_device);
|
|
||||||
|
|
||||||
CommandBufferPool = new VulkanCommandBufferPool(device, physicalDevice);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PixelSize Size { get; private set; }
|
|
||||||
public uint QueueFamilyIndex => _physicalDevice.QueueFamilyIndex;
|
|
||||||
|
|
||||||
internal SurfaceFormatKHR SurfaceFormat
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_surfaceFormat.Format == Format.Undefined)
|
|
||||||
{
|
|
||||||
_surfaceFormat = _surface.GetSurfaceFormat(_physicalDevice);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _surfaceFormat;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_device.WaitIdle();
|
|
||||||
_semaphorePair?.Dispose();
|
|
||||||
DestroyCurrentImageViews();
|
|
||||||
_swapchainExtension.DestroySwapchain(_device.InternalHandle, _swapchain, Span<AllocationCallbacks>.Empty);
|
|
||||||
CommandBufferPool.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsSurfaceChanged()
|
|
||||||
{
|
|
||||||
var changed = _surfaceChanged;
|
|
||||||
_surfaceChanged = false;
|
|
||||||
|
|
||||||
return changed;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static unsafe SwapchainKHR CreateSwapchain(VulkanInstance instance, VulkanDevice device,
|
|
||||||
VulkanPhysicalDevice physicalDevice, VulkanSurface surface, out Extent2D swapchainExtent,
|
|
||||||
SwapchainKHR? oldswapchain = null, bool vsyncEnabled = true)
|
|
||||||
{
|
|
||||||
if (_swapchainExtension == null)
|
|
||||||
{
|
|
||||||
instance.Api.TryGetDeviceExtension(instance.InternalHandle, device.InternalHandle, out _swapchainExtension);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!surface.CanSurfacePresent(physicalDevice))
|
|
||||||
{
|
|
||||||
Thread.Sleep(16);
|
|
||||||
}
|
|
||||||
|
|
||||||
VulkanSurface.SurfaceExtension.GetPhysicalDeviceSurfaceCapabilities(physicalDevice.InternalHandle,
|
|
||||||
surface.ApiHandle, out var capabilities);
|
|
||||||
|
|
||||||
var imageCount = capabilities.MinImageCount + 1;
|
|
||||||
if (capabilities.MaxImageCount > 0 && imageCount > capabilities.MaxImageCount)
|
|
||||||
{
|
|
||||||
imageCount = capabilities.MaxImageCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
var surfaceFormat = surface.GetSurfaceFormat(physicalDevice);
|
|
||||||
|
|
||||||
bool supportsIdentityTransform = capabilities.SupportedTransforms.HasFlag(SurfaceTransformFlagsKHR.SurfaceTransformIdentityBitKhr);
|
|
||||||
bool isRotated = capabilities.CurrentTransform.HasFlag(SurfaceTransformFlagsKHR.SurfaceTransformRotate90BitKhr) ||
|
|
||||||
capabilities.CurrentTransform.HasFlag(SurfaceTransformFlagsKHR.SurfaceTransformRotate270BitKhr);
|
|
||||||
|
|
||||||
swapchainExtent = GetSwapchainExtent(surface, capabilities);
|
|
||||||
|
|
||||||
CompositeAlphaFlagsKHR compositeAlphaFlags = GetSuitableCompositeAlphaFlags(capabilities);
|
|
||||||
|
|
||||||
PresentModeKHR presentMode = GetSuitablePresentMode(physicalDevice, surface, vsyncEnabled);
|
|
||||||
|
|
||||||
var swapchainCreateInfo = new SwapchainCreateInfoKHR
|
|
||||||
{
|
|
||||||
SType = StructureType.SwapchainCreateInfoKhr,
|
|
||||||
Surface = surface.ApiHandle,
|
|
||||||
MinImageCount = imageCount,
|
|
||||||
ImageFormat = surfaceFormat.Format,
|
|
||||||
ImageColorSpace = surfaceFormat.ColorSpace,
|
|
||||||
ImageExtent = swapchainExtent,
|
|
||||||
ImageUsage =
|
|
||||||
ImageUsageFlags.ImageUsageColorAttachmentBit | ImageUsageFlags.ImageUsageTransferDstBit,
|
|
||||||
ImageSharingMode = SharingMode.Exclusive,
|
|
||||||
ImageArrayLayers = 1,
|
|
||||||
PreTransform = supportsIdentityTransform && isRotated ?
|
|
||||||
SurfaceTransformFlagsKHR.SurfaceTransformIdentityBitKhr :
|
|
||||||
capabilities.CurrentTransform,
|
|
||||||
CompositeAlpha = compositeAlphaFlags,
|
|
||||||
PresentMode = presentMode,
|
|
||||||
Clipped = true,
|
|
||||||
OldSwapchain = oldswapchain ?? new SwapchainKHR()
|
|
||||||
};
|
|
||||||
|
|
||||||
_swapchainExtension.CreateSwapchain(device.InternalHandle, swapchainCreateInfo, null, out var swapchain)
|
|
||||||
.ThrowOnError();
|
|
||||||
|
|
||||||
if (oldswapchain != null)
|
|
||||||
{
|
|
||||||
_swapchainExtension.DestroySwapchain(device.InternalHandle, oldswapchain.Value, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
return swapchain;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static unsafe Extent2D GetSwapchainExtent(VulkanSurface surface, SurfaceCapabilitiesKHR capabilities)
|
|
||||||
{
|
|
||||||
Extent2D swapchainExtent;
|
|
||||||
if (capabilities.CurrentExtent.Width != uint.MaxValue)
|
|
||||||
{
|
|
||||||
swapchainExtent = capabilities.CurrentExtent;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var surfaceSize = surface.SurfaceSize;
|
|
||||||
|
|
||||||
var width = Math.Clamp((uint)surfaceSize.Width, capabilities.MinImageExtent.Width, capabilities.MaxImageExtent.Width);
|
|
||||||
var height = Math.Clamp((uint)surfaceSize.Height, capabilities.MinImageExtent.Height, capabilities.MaxImageExtent.Height);
|
|
||||||
|
|
||||||
swapchainExtent = new Extent2D(width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
return swapchainExtent;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static unsafe CompositeAlphaFlagsKHR GetSuitableCompositeAlphaFlags(SurfaceCapabilitiesKHR capabilities)
|
|
||||||
{
|
|
||||||
var compositeAlphaFlags = CompositeAlphaFlagsKHR.CompositeAlphaOpaqueBitKhr;
|
|
||||||
|
|
||||||
if (capabilities.SupportedCompositeAlpha.HasFlag(CompositeAlphaFlagsKHR.CompositeAlphaPostMultipliedBitKhr))
|
|
||||||
{
|
|
||||||
compositeAlphaFlags = CompositeAlphaFlagsKHR.CompositeAlphaPostMultipliedBitKhr;
|
|
||||||
}
|
|
||||||
else if (capabilities.SupportedCompositeAlpha.HasFlag(CompositeAlphaFlagsKHR.CompositeAlphaPreMultipliedBitKhr))
|
|
||||||
{
|
|
||||||
compositeAlphaFlags = CompositeAlphaFlagsKHR.CompositeAlphaPreMultipliedBitKhr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return compositeAlphaFlags;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static unsafe PresentModeKHR GetSuitablePresentMode(VulkanPhysicalDevice physicalDevice, VulkanSurface surface, bool vsyncEnabled)
|
|
||||||
{
|
|
||||||
uint presentModesCount;
|
|
||||||
|
|
||||||
VulkanSurface.SurfaceExtension.GetPhysicalDeviceSurfacePresentModes(physicalDevice.InternalHandle,
|
|
||||||
surface.ApiHandle,
|
|
||||||
&presentModesCount, null);
|
|
||||||
|
|
||||||
var presentModes = new PresentModeKHR[presentModesCount];
|
|
||||||
|
|
||||||
fixed (PresentModeKHR* pPresentModes = presentModes)
|
|
||||||
{
|
|
||||||
VulkanSurface.SurfaceExtension.GetPhysicalDeviceSurfacePresentModes(physicalDevice.InternalHandle,
|
|
||||||
surface.ApiHandle, &presentModesCount, pPresentModes);
|
|
||||||
}
|
|
||||||
|
|
||||||
var modes = presentModes.ToList();
|
|
||||||
|
|
||||||
if (!vsyncEnabled && modes.Contains(PresentModeKHR.PresentModeImmediateKhr))
|
|
||||||
{
|
|
||||||
return PresentModeKHR.PresentModeImmediateKhr;
|
|
||||||
}
|
|
||||||
else if (modes.Contains(PresentModeKHR.PresentModeMailboxKhr))
|
|
||||||
{
|
|
||||||
return PresentModeKHR.PresentModeMailboxKhr;
|
|
||||||
}
|
|
||||||
else if (modes.Contains(PresentModeKHR.PresentModeFifoKhr))
|
|
||||||
{
|
|
||||||
return PresentModeKHR.PresentModeFifoKhr;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return PresentModeKHR.PresentModeImmediateKhr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static VulkanDisplay CreateDisplay(VulkanInstance instance, VulkanDevice device,
|
|
||||||
VulkanPhysicalDevice physicalDevice, VulkanSurface surface)
|
|
||||||
{
|
|
||||||
var swapchain = CreateSwapchain(instance, device, physicalDevice, surface, out var extent, null, true);
|
|
||||||
|
|
||||||
return new VulkanDisplay(instance, device, physicalDevice, surface, swapchain, extent);
|
|
||||||
}
|
|
||||||
|
|
||||||
private unsafe void CreateSwapchainImages()
|
|
||||||
{
|
|
||||||
DestroyCurrentImageViews();
|
|
||||||
|
|
||||||
Size = new PixelSize((int)_swapchainExtent.Width, (int)_swapchainExtent.Height);
|
|
||||||
|
|
||||||
uint imageCount = 0;
|
|
||||||
|
|
||||||
_swapchainExtension.GetSwapchainImages(_device.InternalHandle, _swapchain, &imageCount, null);
|
|
||||||
|
|
||||||
_swapchainImages = new Image[imageCount];
|
|
||||||
|
|
||||||
fixed (Image* pSwapchainImages = _swapchainImages)
|
|
||||||
{
|
|
||||||
_swapchainExtension.GetSwapchainImages(_device.InternalHandle, _swapchain, &imageCount, pSwapchainImages);
|
|
||||||
}
|
|
||||||
|
|
||||||
_swapchainImageViews = new ImageView[imageCount];
|
|
||||||
|
|
||||||
var surfaceFormat = SurfaceFormat;
|
|
||||||
|
|
||||||
for (var i = 0; i < imageCount; i++)
|
|
||||||
{
|
|
||||||
_swapchainImageViews[i] = CreateSwapchainImageView(_swapchainImages[i], surfaceFormat.Format);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DestroyCurrentImageViews()
|
|
||||||
{
|
|
||||||
for (var i = 0; i < _swapchainImageViews.Length; i++)
|
|
||||||
{
|
|
||||||
_instance.Api.DestroyImageView(_device.InternalHandle, _swapchainImageViews[i], Span<AllocationCallbacks>.Empty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void ChangeVSyncMode(bool vsyncEnabled)
|
|
||||||
{
|
|
||||||
_vsyncStateChanged = true;
|
|
||||||
_vsyncEnabled = vsyncEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Recreate()
|
|
||||||
{
|
|
||||||
_device.WaitIdle();
|
|
||||||
_swapchain = CreateSwapchain(_instance, _device, _physicalDevice, _surface, out _swapchainExtent, _swapchain, _vsyncEnabled);
|
|
||||||
|
|
||||||
CreateSwapchainImages();
|
|
||||||
|
|
||||||
_surfaceChanged = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private unsafe ImageView CreateSwapchainImageView(Image swapchainImage, Format format)
|
|
||||||
{
|
|
||||||
var componentMapping = new ComponentMapping(
|
|
||||||
ComponentSwizzle.Identity,
|
|
||||||
ComponentSwizzle.Identity,
|
|
||||||
ComponentSwizzle.Identity,
|
|
||||||
ComponentSwizzle.Identity);
|
|
||||||
|
|
||||||
var subresourceRange = new ImageSubresourceRange(ImageAspectFlags.ImageAspectColorBit, 0, 1, 0, 1);
|
|
||||||
|
|
||||||
var imageCreateInfo = new ImageViewCreateInfo
|
|
||||||
{
|
|
||||||
SType = StructureType.ImageViewCreateInfo,
|
|
||||||
Image = swapchainImage,
|
|
||||||
ViewType = ImageViewType.ImageViewType2D,
|
|
||||||
Format = format,
|
|
||||||
Components = componentMapping,
|
|
||||||
SubresourceRange = subresourceRange
|
|
||||||
};
|
|
||||||
|
|
||||||
_instance.Api.CreateImageView(_device.InternalHandle, imageCreateInfo, null, out var imageView).ThrowOnError();
|
|
||||||
return imageView;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool EnsureSwapchainAvailable()
|
|
||||||
{
|
|
||||||
if (Size != _surface.SurfaceSize || _vsyncStateChanged)
|
|
||||||
{
|
|
||||||
_vsyncStateChanged = false;
|
|
||||||
|
|
||||||
Recreate();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal VulkanCommandBufferPool.VulkanCommandBuffer StartPresentation()
|
|
||||||
{
|
|
||||||
_nextImage = 0;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
var acquireResult = _swapchainExtension.AcquireNextImage(
|
|
||||||
_device.InternalHandle,
|
|
||||||
_swapchain,
|
|
||||||
ulong.MaxValue,
|
|
||||||
_semaphorePair.ImageAvailableSemaphore,
|
|
||||||
new Fence(),
|
|
||||||
ref _nextImage);
|
|
||||||
|
|
||||||
if (acquireResult == Result.ErrorOutOfDateKhr ||
|
|
||||||
acquireResult == Result.SuboptimalKhr)
|
|
||||||
{
|
|
||||||
Recreate();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
acquireResult.ThrowOnError();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var commandBuffer = CommandBufferPool.CreateCommandBuffer();
|
|
||||||
commandBuffer.BeginRecording();
|
|
||||||
|
|
||||||
VulkanMemoryHelper.TransitionLayout(_device, commandBuffer.InternalHandle,
|
|
||||||
_swapchainImages[_nextImage], ImageLayout.Undefined,
|
|
||||||
AccessFlags.AccessNoneKhr,
|
|
||||||
ImageLayout.TransferDstOptimal,
|
|
||||||
AccessFlags.AccessTransferWriteBit,
|
|
||||||
1);
|
|
||||||
|
|
||||||
return commandBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void BlitImageToCurrentImage(VulkanSurfaceRenderTarget renderTarget, CommandBuffer commandBuffer)
|
|
||||||
{
|
|
||||||
var image = renderTarget.GetImage();
|
|
||||||
|
|
||||||
VulkanMemoryHelper.TransitionLayout(_device, commandBuffer,
|
|
||||||
image.InternalHandle.Value, (ImageLayout)image.CurrentLayout,
|
|
||||||
AccessFlags.AccessNoneKhr,
|
|
||||||
ImageLayout.TransferSrcOptimal,
|
|
||||||
AccessFlags.AccessTransferReadBit,
|
|
||||||
renderTarget.MipLevels);
|
|
||||||
|
|
||||||
var srcBlitRegion = new ImageBlit
|
|
||||||
{
|
|
||||||
SrcOffsets = new ImageBlit.SrcOffsetsBuffer
|
|
||||||
{
|
|
||||||
Element0 = new Offset3D(0, 0, 0),
|
|
||||||
Element1 = new Offset3D(renderTarget.Size.Width, renderTarget.Size.Height, 1),
|
|
||||||
},
|
|
||||||
DstOffsets = new ImageBlit.DstOffsetsBuffer
|
|
||||||
{
|
|
||||||
Element0 = new Offset3D(0, 0, 0),
|
|
||||||
Element1 = new Offset3D(Size.Width, Size.Height, 1),
|
|
||||||
},
|
|
||||||
SrcSubresource = new ImageSubresourceLayers
|
|
||||||
{
|
|
||||||
AspectMask = ImageAspectFlags.ImageAspectColorBit,
|
|
||||||
BaseArrayLayer = 0,
|
|
||||||
LayerCount = 1,
|
|
||||||
MipLevel = 0
|
|
||||||
},
|
|
||||||
DstSubresource = new ImageSubresourceLayers
|
|
||||||
{
|
|
||||||
AspectMask = ImageAspectFlags.ImageAspectColorBit,
|
|
||||||
BaseArrayLayer = 0,
|
|
||||||
LayerCount = 1,
|
|
||||||
MipLevel = 0
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
_device.Api.CmdBlitImage(commandBuffer, image.InternalHandle.Value,
|
|
||||||
ImageLayout.TransferSrcOptimal,
|
|
||||||
_swapchainImages[_nextImage],
|
|
||||||
ImageLayout.TransferDstOptimal,
|
|
||||||
1,
|
|
||||||
srcBlitRegion,
|
|
||||||
Filter.Linear);
|
|
||||||
|
|
||||||
VulkanMemoryHelper.TransitionLayout(_device, commandBuffer,
|
|
||||||
image.InternalHandle.Value, ImageLayout.TransferSrcOptimal,
|
|
||||||
AccessFlags.AccessTransferReadBit,
|
|
||||||
(ImageLayout)image.CurrentLayout,
|
|
||||||
AccessFlags.AccessNoneKhr,
|
|
||||||
renderTarget.MipLevels);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal unsafe void EndPresentation(VulkanCommandBufferPool.VulkanCommandBuffer commandBuffer)
|
|
||||||
{
|
|
||||||
VulkanMemoryHelper.TransitionLayout(_device, commandBuffer.InternalHandle,
|
|
||||||
_swapchainImages[_nextImage], ImageLayout.TransferDstOptimal,
|
|
||||||
AccessFlags.AccessNoneKhr,
|
|
||||||
ImageLayout.PresentSrcKhr,
|
|
||||||
AccessFlags.AccessNoneKhr,
|
|
||||||
1);
|
|
||||||
|
|
||||||
commandBuffer.Submit(
|
|
||||||
stackalloc[] { _semaphorePair.ImageAvailableSemaphore },
|
|
||||||
stackalloc[] { PipelineStageFlags.PipelineStageColorAttachmentOutputBit },
|
|
||||||
stackalloc[] { _semaphorePair.RenderFinishedSemaphore });
|
|
||||||
|
|
||||||
var semaphore = _semaphorePair.RenderFinishedSemaphore;
|
|
||||||
var swapchain = _swapchain;
|
|
||||||
var nextImage = _nextImage;
|
|
||||||
|
|
||||||
Result result;
|
|
||||||
|
|
||||||
var presentInfo = new PresentInfoKHR
|
|
||||||
{
|
|
||||||
SType = StructureType.PresentInfoKhr,
|
|
||||||
WaitSemaphoreCount = 1,
|
|
||||||
PWaitSemaphores = &semaphore,
|
|
||||||
SwapchainCount = 1,
|
|
||||||
PSwapchains = &swapchain,
|
|
||||||
PImageIndices = &nextImage,
|
|
||||||
PResults = &result
|
|
||||||
};
|
|
||||||
|
|
||||||
lock (_device.Lock)
|
|
||||||
{
|
|
||||||
_swapchainExtension.QueuePresent(_device.PresentQueue.InternalHandle, presentInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
CommandBufferPool.FreeUsedCommandBuffers();
|
|
||||||
|
|
||||||
Presented?.Invoke(this, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,165 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Avalonia;
|
|
||||||
using Silk.NET.Vulkan;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Vulkan
|
|
||||||
{
|
|
||||||
internal class VulkanImage : IDisposable
|
|
||||||
{
|
|
||||||
private readonly VulkanDevice _device;
|
|
||||||
private readonly VulkanPhysicalDevice _physicalDevice;
|
|
||||||
private readonly VulkanCommandBufferPool _commandBufferPool;
|
|
||||||
private ImageLayout _currentLayout;
|
|
||||||
private AccessFlags _currentAccessFlags;
|
|
||||||
private ImageUsageFlags _imageUsageFlags { get; }
|
|
||||||
private ImageView? _imageView { get; set; }
|
|
||||||
private DeviceMemory _imageMemory { get; set; }
|
|
||||||
|
|
||||||
internal Image? InternalHandle { get; private set; }
|
|
||||||
internal Format Format { get; }
|
|
||||||
internal ImageAspectFlags AspectFlags { get; private set; }
|
|
||||||
|
|
||||||
public ulong Handle => InternalHandle?.Handle ?? 0;
|
|
||||||
public ulong ViewHandle => _imageView?.Handle ?? 0;
|
|
||||||
public uint UsageFlags => (uint)_imageUsageFlags;
|
|
||||||
public ulong MemoryHandle => _imageMemory.Handle;
|
|
||||||
public uint MipLevels { get; private set; }
|
|
||||||
public PixelSize Size { get; }
|
|
||||||
public ulong MemorySize { get; private set; }
|
|
||||||
public uint CurrentLayout => (uint)_currentLayout;
|
|
||||||
|
|
||||||
public VulkanImage(
|
|
||||||
VulkanDevice device,
|
|
||||||
VulkanPhysicalDevice physicalDevice,
|
|
||||||
VulkanCommandBufferPool commandBufferPool,
|
|
||||||
uint format,
|
|
||||||
PixelSize size,
|
|
||||||
uint mipLevels = 0)
|
|
||||||
{
|
|
||||||
_device = device;
|
|
||||||
_physicalDevice = physicalDevice;
|
|
||||||
_commandBufferPool = commandBufferPool;
|
|
||||||
Format = (Format)format;
|
|
||||||
Size = size;
|
|
||||||
MipLevels = mipLevels;
|
|
||||||
_imageUsageFlags =
|
|
||||||
ImageUsageFlags.ImageUsageColorAttachmentBit | ImageUsageFlags.ImageUsageTransferDstBit |
|
|
||||||
ImageUsageFlags.ImageUsageTransferSrcBit | ImageUsageFlags.ImageUsageSampledBit;
|
|
||||||
|
|
||||||
Initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
public unsafe void Initialize()
|
|
||||||
{
|
|
||||||
if (!InternalHandle.HasValue)
|
|
||||||
{
|
|
||||||
MipLevels = MipLevels != 0 ? MipLevels : (uint)Math.Floor(Math.Log(Math.Max(Size.Width, Size.Height), 2));
|
|
||||||
|
|
||||||
var imageCreateInfo = new ImageCreateInfo
|
|
||||||
{
|
|
||||||
SType = StructureType.ImageCreateInfo,
|
|
||||||
ImageType = ImageType.ImageType2D,
|
|
||||||
Format = Format,
|
|
||||||
Extent = new Extent3D((uint?)Size.Width, (uint?)Size.Height, 1),
|
|
||||||
MipLevels = MipLevels,
|
|
||||||
ArrayLayers = 1,
|
|
||||||
Samples = SampleCountFlags.SampleCount1Bit,
|
|
||||||
Tiling = Tiling,
|
|
||||||
Usage = _imageUsageFlags,
|
|
||||||
SharingMode = SharingMode.Exclusive,
|
|
||||||
InitialLayout = ImageLayout.Undefined,
|
|
||||||
Flags = ImageCreateFlags.ImageCreateMutableFormatBit
|
|
||||||
};
|
|
||||||
|
|
||||||
_device.Api.CreateImage(_device.InternalHandle, imageCreateInfo, null, out var image).ThrowOnError();
|
|
||||||
InternalHandle = image;
|
|
||||||
|
|
||||||
_device.Api.GetImageMemoryRequirements(_device.InternalHandle, InternalHandle.Value,
|
|
||||||
out var memoryRequirements);
|
|
||||||
|
|
||||||
var memoryAllocateInfo = new MemoryAllocateInfo
|
|
||||||
{
|
|
||||||
SType = StructureType.MemoryAllocateInfo,
|
|
||||||
AllocationSize = memoryRequirements.Size,
|
|
||||||
MemoryTypeIndex = (uint)VulkanMemoryHelper.FindSuitableMemoryTypeIndex(
|
|
||||||
_physicalDevice,
|
|
||||||
memoryRequirements.MemoryTypeBits, MemoryPropertyFlags.MemoryPropertyDeviceLocalBit)
|
|
||||||
};
|
|
||||||
|
|
||||||
_device.Api.AllocateMemory(_device.InternalHandle, memoryAllocateInfo, null,
|
|
||||||
out var imageMemory);
|
|
||||||
|
|
||||||
_imageMemory = imageMemory;
|
|
||||||
|
|
||||||
_device.Api.BindImageMemory(_device.InternalHandle, InternalHandle.Value, _imageMemory, 0);
|
|
||||||
|
|
||||||
MemorySize = memoryRequirements.Size;
|
|
||||||
|
|
||||||
var componentMapping = new ComponentMapping(
|
|
||||||
ComponentSwizzle.Identity,
|
|
||||||
ComponentSwizzle.Identity,
|
|
||||||
ComponentSwizzle.Identity,
|
|
||||||
ComponentSwizzle.Identity);
|
|
||||||
|
|
||||||
AspectFlags = ImageAspectFlags.ImageAspectColorBit;
|
|
||||||
|
|
||||||
var subresourceRange = new ImageSubresourceRange(AspectFlags, 0, MipLevels, 0, 1);
|
|
||||||
|
|
||||||
var imageViewCreateInfo = new ImageViewCreateInfo
|
|
||||||
{
|
|
||||||
SType = StructureType.ImageViewCreateInfo,
|
|
||||||
Image = InternalHandle.Value,
|
|
||||||
ViewType = ImageViewType.ImageViewType2D,
|
|
||||||
Format = Format,
|
|
||||||
Components = componentMapping,
|
|
||||||
SubresourceRange = subresourceRange
|
|
||||||
};
|
|
||||||
|
|
||||||
_device.Api
|
|
||||||
.CreateImageView(_device.InternalHandle, imageViewCreateInfo, null, out var imageView)
|
|
||||||
.ThrowOnError();
|
|
||||||
|
|
||||||
_imageView = imageView;
|
|
||||||
|
|
||||||
_currentLayout = ImageLayout.Undefined;
|
|
||||||
|
|
||||||
TransitionLayout(ImageLayout.ColorAttachmentOptimal, AccessFlags.AccessNoneKhr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ImageTiling Tiling => ImageTiling.Optimal;
|
|
||||||
|
|
||||||
internal void TransitionLayout(ImageLayout destinationLayout, AccessFlags destinationAccessFlags)
|
|
||||||
{
|
|
||||||
var commandBuffer = _commandBufferPool.CreateCommandBuffer();
|
|
||||||
commandBuffer.BeginRecording();
|
|
||||||
|
|
||||||
VulkanMemoryHelper.TransitionLayout(_device, commandBuffer.InternalHandle, InternalHandle.Value,
|
|
||||||
_currentLayout,
|
|
||||||
_currentAccessFlags,
|
|
||||||
destinationLayout, destinationAccessFlags,
|
|
||||||
MipLevels);
|
|
||||||
|
|
||||||
commandBuffer.EndRecording();
|
|
||||||
|
|
||||||
commandBuffer.Submit();
|
|
||||||
|
|
||||||
_currentLayout = destinationLayout;
|
|
||||||
_currentAccessFlags = destinationAccessFlags;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (InternalHandle != null)
|
|
||||||
{
|
|
||||||
_device.Api.DestroyImageView(_device.InternalHandle, _imageView.Value, Span<AllocationCallbacks>.Empty);
|
|
||||||
_device.Api.DestroyImage(_device.InternalHandle, InternalHandle.Value, Span<AllocationCallbacks>.Empty);
|
|
||||||
_device.Api.FreeMemory(_device.InternalHandle, _imageMemory, Span<AllocationCallbacks>.Empty);
|
|
||||||
|
|
||||||
_imageView = default;
|
|
||||||
InternalHandle = null;
|
|
||||||
_imageMemory = default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,135 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using Silk.NET.Core;
|
|
||||||
using Silk.NET.Vulkan;
|
|
||||||
using Silk.NET.Vulkan.Extensions.EXT;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Vulkan
|
|
||||||
{
|
|
||||||
public class VulkanInstance : IDisposable
|
|
||||||
{
|
|
||||||
private const string EngineName = "Avalonia Vulkan";
|
|
||||||
|
|
||||||
private VulkanInstance(Instance apiHandle, Vk api)
|
|
||||||
{
|
|
||||||
InternalHandle = apiHandle;
|
|
||||||
Api = api;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IntPtr Handle => InternalHandle.Handle;
|
|
||||||
|
|
||||||
internal Instance InternalHandle { get; }
|
|
||||||
public Vk Api { get; }
|
|
||||||
|
|
||||||
internal static IEnumerable<string> RequiredInstanceExtensions
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
yield return "VK_KHR_surface";
|
|
||||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
|
||||||
{
|
|
||||||
yield return "VK_KHR_xlib_surface";
|
|
||||||
}
|
|
||||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|
||||||
{
|
|
||||||
yield return "VK_KHR_win32_surface";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Api?.DestroyInstance(InternalHandle, Span<AllocationCallbacks>.Empty);
|
|
||||||
Api?.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static unsafe VulkanInstance Create(VulkanOptions options)
|
|
||||||
{
|
|
||||||
var api = Vk.GetApi();
|
|
||||||
var applicationName = Marshal.StringToHGlobalAnsi(options.ApplicationName);
|
|
||||||
var engineName = Marshal.StringToHGlobalAnsi(EngineName);
|
|
||||||
var enabledExtensions = new List<string>(options.InstanceExtensions);
|
|
||||||
|
|
||||||
enabledExtensions.AddRange(RequiredInstanceExtensions);
|
|
||||||
|
|
||||||
var applicationInfo = new ApplicationInfo
|
|
||||||
{
|
|
||||||
PApplicationName = (byte*)applicationName,
|
|
||||||
ApiVersion = Vk.Version12.Value,
|
|
||||||
PEngineName = (byte*)engineName,
|
|
||||||
EngineVersion = new Version32(1, 0, 0),
|
|
||||||
ApplicationVersion = new Version32(1, 0, 0)
|
|
||||||
};
|
|
||||||
|
|
||||||
var enabledLayers = new HashSet<string>();
|
|
||||||
|
|
||||||
if (options.UseDebug)
|
|
||||||
{
|
|
||||||
enabledExtensions.Add(ExtDebugUtils.ExtensionName);
|
|
||||||
enabledExtensions.Add(ExtDebugReport.ExtensionName);
|
|
||||||
if (IsLayerAvailable(api, "VK_LAYER_KHRONOS_validation"))
|
|
||||||
enabledLayers.Add("VK_LAYER_KHRONOS_validation");
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var layer in options.EnabledLayers)
|
|
||||||
enabledLayers.Add(layer);
|
|
||||||
|
|
||||||
var ppEnabledExtensions = stackalloc IntPtr[enabledExtensions.Count];
|
|
||||||
var ppEnabledLayers = stackalloc IntPtr[enabledLayers.Count];
|
|
||||||
|
|
||||||
for (var i = 0; i < enabledExtensions.Count; i++)
|
|
||||||
ppEnabledExtensions[i] = Marshal.StringToHGlobalAnsi(enabledExtensions[i]);
|
|
||||||
|
|
||||||
var layers = enabledLayers.ToList();
|
|
||||||
|
|
||||||
for (var i = 0; i < enabledLayers.Count; i++)
|
|
||||||
ppEnabledLayers[i] = Marshal.StringToHGlobalAnsi(layers[i]);
|
|
||||||
|
|
||||||
var instanceCreateInfo = new InstanceCreateInfo
|
|
||||||
{
|
|
||||||
SType = StructureType.InstanceCreateInfo,
|
|
||||||
PApplicationInfo = &applicationInfo,
|
|
||||||
PpEnabledExtensionNames = (byte**)ppEnabledExtensions,
|
|
||||||
PpEnabledLayerNames = (byte**)ppEnabledLayers,
|
|
||||||
EnabledExtensionCount = (uint)enabledExtensions.Count,
|
|
||||||
EnabledLayerCount = (uint)enabledLayers.Count
|
|
||||||
};
|
|
||||||
|
|
||||||
api.CreateInstance(in instanceCreateInfo, null, out var instance).ThrowOnError();
|
|
||||||
|
|
||||||
Marshal.FreeHGlobal(applicationName);
|
|
||||||
Marshal.FreeHGlobal(engineName);
|
|
||||||
|
|
||||||
for (var i = 0; i < enabledExtensions.Count; i++) Marshal.FreeHGlobal(ppEnabledExtensions[i]);
|
|
||||||
|
|
||||||
for (var i = 0; i < enabledLayers.Count; i++) Marshal.FreeHGlobal(ppEnabledLayers[i]);
|
|
||||||
|
|
||||||
return new VulkanInstance(instance, api);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static unsafe bool IsLayerAvailable(Vk api, string layerName)
|
|
||||||
{
|
|
||||||
uint layerPropertiesCount;
|
|
||||||
|
|
||||||
api.EnumerateInstanceLayerProperties(&layerPropertiesCount, null).ThrowOnError();
|
|
||||||
|
|
||||||
var layerProperties = new LayerProperties[layerPropertiesCount];
|
|
||||||
|
|
||||||
fixed (LayerProperties* pLayerProperties = layerProperties)
|
|
||||||
{
|
|
||||||
api.EnumerateInstanceLayerProperties(&layerPropertiesCount, layerProperties).ThrowOnError();
|
|
||||||
|
|
||||||
for (var i = 0; i < layerPropertiesCount; i++)
|
|
||||||
{
|
|
||||||
var currentLayerName = Marshal.PtrToStringAnsi((IntPtr)pLayerProperties[i].LayerName);
|
|
||||||
|
|
||||||
if (currentLayerName == layerName) return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,59 +0,0 @@
|
|||||||
using Silk.NET.Vulkan;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Vulkan
|
|
||||||
{
|
|
||||||
internal static class VulkanMemoryHelper
|
|
||||||
{
|
|
||||||
internal static int FindSuitableMemoryTypeIndex(VulkanPhysicalDevice physicalDevice, uint memoryTypeBits,
|
|
||||||
MemoryPropertyFlags flags)
|
|
||||||
{
|
|
||||||
physicalDevice.Api.GetPhysicalDeviceMemoryProperties(physicalDevice.InternalHandle, out var properties);
|
|
||||||
|
|
||||||
for (var i = 0; i < properties.MemoryTypeCount; i++)
|
|
||||||
{
|
|
||||||
var type = properties.MemoryTypes[i];
|
|
||||||
|
|
||||||
if ((memoryTypeBits & (1 << i)) != 0 && type.PropertyFlags.HasFlag(flags)) return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static unsafe void TransitionLayout(VulkanDevice device,
|
|
||||||
CommandBuffer commandBuffer,
|
|
||||||
Image image,
|
|
||||||
ImageLayout sourceLayout,
|
|
||||||
AccessFlags sourceAccessMask,
|
|
||||||
ImageLayout destinationLayout,
|
|
||||||
AccessFlags destinationAccessMask,
|
|
||||||
uint mipLevels)
|
|
||||||
{
|
|
||||||
var subresourceRange = new ImageSubresourceRange(ImageAspectFlags.ImageAspectColorBit, 0, mipLevels, 0, 1);
|
|
||||||
|
|
||||||
var barrier = new ImageMemoryBarrier
|
|
||||||
{
|
|
||||||
SType = StructureType.ImageMemoryBarrier,
|
|
||||||
SrcAccessMask = sourceAccessMask,
|
|
||||||
DstAccessMask = destinationAccessMask,
|
|
||||||
OldLayout = sourceLayout,
|
|
||||||
NewLayout = destinationLayout,
|
|
||||||
SrcQueueFamilyIndex = Vk.QueueFamilyIgnored,
|
|
||||||
DstQueueFamilyIndex = Vk.QueueFamilyIgnored,
|
|
||||||
Image = image,
|
|
||||||
SubresourceRange = subresourceRange
|
|
||||||
};
|
|
||||||
|
|
||||||
device.Api.CmdPipelineBarrier(
|
|
||||||
commandBuffer,
|
|
||||||
PipelineStageFlags.PipelineStageAllCommandsBit,
|
|
||||||
PipelineStageFlags.PipelineStageAllCommandsBit,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
null,
|
|
||||||
0,
|
|
||||||
null,
|
|
||||||
1,
|
|
||||||
barrier);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,44 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Vulkan
|
|
||||||
{
|
|
||||||
public class VulkanOptions
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the application name of the Vulkan instance
|
|
||||||
/// </summary>
|
|
||||||
public string ApplicationName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Specifies additional extensions to enable if available on the instance
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<string> InstanceExtensions { get; set; } = Enumerable.Empty<string>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Specifies layers to enable if available on the instance
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<string> EnabledLayers { get; set; } = Enumerable.Empty<string>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Enables the debug layer
|
|
||||||
/// </summary>
|
|
||||||
public bool UseDebug { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Selects the first suitable discrete GPU available
|
|
||||||
/// </summary>
|
|
||||||
public bool PreferDiscreteGpu { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the device to use if available and suitable.
|
|
||||||
/// </summary>
|
|
||||||
public string PreferredDevice { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Max number of device queues to request
|
|
||||||
/// </summary>
|
|
||||||
public uint MaxQueueCount { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,219 +0,0 @@
|
|||||||
using Ryujinx.Graphics.Vulkan;
|
|
||||||
using Silk.NET.Core;
|
|
||||||
using Silk.NET.Vulkan;
|
|
||||||
using Silk.NET.Vulkan.Extensions.KHR;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Vulkan
|
|
||||||
{
|
|
||||||
public unsafe class VulkanPhysicalDevice
|
|
||||||
{
|
|
||||||
private VulkanPhysicalDevice(PhysicalDevice apiHandle, Vk api, uint queueCount, uint queueFamilyIndex)
|
|
||||||
{
|
|
||||||
InternalHandle = apiHandle;
|
|
||||||
Api = api;
|
|
||||||
QueueCount = queueCount;
|
|
||||||
QueueFamilyIndex = queueFamilyIndex;
|
|
||||||
|
|
||||||
api.GetPhysicalDeviceProperties(apiHandle, out var properties);
|
|
||||||
|
|
||||||
DeviceName = Marshal.PtrToStringAnsi((IntPtr)properties.DeviceName);
|
|
||||||
DeviceId = VulkanInitialization.StringFromIdPair(properties.VendorID, properties.DeviceID);
|
|
||||||
|
|
||||||
var version = (Version32)properties.ApiVersion;
|
|
||||||
ApiVersion = new Version((int)version.Major, (int)version.Minor, 0, (int)version.Patch);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal PhysicalDevice InternalHandle { get; }
|
|
||||||
internal Vk Api { get; }
|
|
||||||
public uint QueueCount { get; }
|
|
||||||
public uint QueueFamilyIndex { get; }
|
|
||||||
public IntPtr Handle => InternalHandle.Handle;
|
|
||||||
|
|
||||||
public string DeviceName { get; }
|
|
||||||
public string DeviceId { get; }
|
|
||||||
public Version ApiVersion { get; }
|
|
||||||
public static Dictionary<PhysicalDevice, PhysicalDeviceProperties> PhysicalDevices { get; private set; }
|
|
||||||
public static IEnumerable<KeyValuePair<PhysicalDevice, PhysicalDeviceProperties>> SuitableDevices { get; private set; }
|
|
||||||
|
|
||||||
internal static void SelectAvailableDevices(VulkanInstance instance,
|
|
||||||
VulkanSurface surface, bool preferDiscreteGpu, string preferredDevice)
|
|
||||||
{
|
|
||||||
uint physicalDeviceCount;
|
|
||||||
|
|
||||||
instance.Api.EnumeratePhysicalDevices(instance.InternalHandle, &physicalDeviceCount, null).ThrowOnError();
|
|
||||||
|
|
||||||
var physicalDevices = new PhysicalDevice[physicalDeviceCount];
|
|
||||||
|
|
||||||
fixed (PhysicalDevice* pPhysicalDevices = physicalDevices)
|
|
||||||
{
|
|
||||||
instance.Api.EnumeratePhysicalDevices(instance.InternalHandle, &physicalDeviceCount, pPhysicalDevices)
|
|
||||||
.ThrowOnError();
|
|
||||||
}
|
|
||||||
|
|
||||||
PhysicalDevices = new Dictionary<PhysicalDevice, PhysicalDeviceProperties>();
|
|
||||||
|
|
||||||
foreach (var physicalDevice in physicalDevices)
|
|
||||||
{
|
|
||||||
instance.Api.GetPhysicalDeviceProperties(physicalDevice, out var properties);
|
|
||||||
PhysicalDevices.Add(physicalDevice, properties);
|
|
||||||
}
|
|
||||||
|
|
||||||
SuitableDevices = PhysicalDevices.Where(x => IsSuitableDevice(
|
|
||||||
instance.Api,
|
|
||||||
x.Key,
|
|
||||||
x.Value,
|
|
||||||
surface.ApiHandle,
|
|
||||||
out _,
|
|
||||||
out _));
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static VulkanPhysicalDevice FindSuitablePhysicalDevice(VulkanInstance instance,
|
|
||||||
VulkanSurface surface, bool preferDiscreteGpu, string preferredDevice)
|
|
||||||
{
|
|
||||||
SelectAvailableDevices(instance, surface, preferDiscreteGpu, preferredDevice);
|
|
||||||
|
|
||||||
uint queueFamilyIndex = 0;
|
|
||||||
uint queueCount = 0;
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(preferredDevice))
|
|
||||||
{
|
|
||||||
var physicalDevice = SuitableDevices.FirstOrDefault(x => VulkanInitialization.StringFromIdPair(x.Value.VendorID, x.Value.DeviceID) == preferredDevice);
|
|
||||||
|
|
||||||
queueFamilyIndex = FindSuitableQueueFamily(instance.Api, physicalDevice.Key,
|
|
||||||
surface.ApiHandle, out queueCount);
|
|
||||||
if (queueFamilyIndex != int.MaxValue)
|
|
||||||
{
|
|
||||||
return new VulkanPhysicalDevice(physicalDevice.Key, instance.Api, queueCount, queueFamilyIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (preferDiscreteGpu)
|
|
||||||
{
|
|
||||||
var discreteGpus = SuitableDevices.Where(p => p.Value.DeviceType == PhysicalDeviceType.DiscreteGpu);
|
|
||||||
|
|
||||||
foreach (var gpu in discreteGpus)
|
|
||||||
{
|
|
||||||
queueFamilyIndex = FindSuitableQueueFamily(instance.Api, gpu.Key,
|
|
||||||
surface.ApiHandle, out queueCount);
|
|
||||||
if (queueFamilyIndex != int.MaxValue)
|
|
||||||
{
|
|
||||||
return new VulkanPhysicalDevice(gpu.Key, instance.Api, queueCount, queueFamilyIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var physicalDevice in SuitableDevices)
|
|
||||||
{
|
|
||||||
queueFamilyIndex = FindSuitableQueueFamily(instance.Api, physicalDevice.Key,
|
|
||||||
surface.ApiHandle, out queueCount);
|
|
||||||
if (queueFamilyIndex != int.MaxValue)
|
|
||||||
{
|
|
||||||
return new VulkanPhysicalDevice(physicalDevice.Key, instance.Api, queueCount, queueFamilyIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Exception("No suitable physical device found");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static unsafe bool IsSuitableDevice(Vk api, PhysicalDevice physicalDevice, PhysicalDeviceProperties properties, SurfaceKHR surface,
|
|
||||||
out uint queueCount, out uint familyIndex)
|
|
||||||
{
|
|
||||||
queueCount = 0;
|
|
||||||
familyIndex = 0;
|
|
||||||
|
|
||||||
if (properties.DeviceType == PhysicalDeviceType.Cpu) return false;
|
|
||||||
|
|
||||||
var extensionMatches = 0;
|
|
||||||
uint propertiesCount;
|
|
||||||
|
|
||||||
api.EnumerateDeviceExtensionProperties(physicalDevice, (byte*)null, &propertiesCount, null).ThrowOnError();
|
|
||||||
|
|
||||||
var extensionProperties = new ExtensionProperties[propertiesCount];
|
|
||||||
|
|
||||||
fixed (ExtensionProperties* pExtensionProperties = extensionProperties)
|
|
||||||
{
|
|
||||||
api.EnumerateDeviceExtensionProperties(
|
|
||||||
physicalDevice,
|
|
||||||
(byte*)null,
|
|
||||||
&propertiesCount,
|
|
||||||
pExtensionProperties).ThrowOnError();
|
|
||||||
|
|
||||||
for (var i = 0; i < propertiesCount; i++)
|
|
||||||
{
|
|
||||||
var extensionName = Marshal.PtrToStringAnsi((IntPtr)pExtensionProperties[i].ExtensionName);
|
|
||||||
|
|
||||||
if (VulkanInitialization.RequiredExtensions.Contains(extensionName))
|
|
||||||
{
|
|
||||||
extensionMatches++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (extensionMatches == VulkanInitialization.RequiredExtensions.Length)
|
|
||||||
{
|
|
||||||
familyIndex = FindSuitableQueueFamily(api, physicalDevice, surface, out queueCount);
|
|
||||||
|
|
||||||
return familyIndex != uint.MaxValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal unsafe string[] GetSupportedExtensions()
|
|
||||||
{
|
|
||||||
uint propertiesCount;
|
|
||||||
|
|
||||||
Api.EnumerateDeviceExtensionProperties(InternalHandle, (byte*)null, &propertiesCount, null).ThrowOnError();
|
|
||||||
|
|
||||||
var extensionProperties = new ExtensionProperties[propertiesCount];
|
|
||||||
|
|
||||||
fixed (ExtensionProperties* pExtensionProperties = extensionProperties)
|
|
||||||
{
|
|
||||||
Api.EnumerateDeviceExtensionProperties(InternalHandle, (byte*)null, &propertiesCount, pExtensionProperties)
|
|
||||||
.ThrowOnError();
|
|
||||||
}
|
|
||||||
|
|
||||||
return extensionProperties.Select(x => Marshal.PtrToStringAnsi((IntPtr)x.ExtensionName)).ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static uint FindSuitableQueueFamily(Vk api, PhysicalDevice physicalDevice, SurfaceKHR surface,
|
|
||||||
out uint queueCount)
|
|
||||||
{
|
|
||||||
const QueueFlags RequiredFlags = QueueFlags.QueueGraphicsBit | QueueFlags.QueueComputeBit;
|
|
||||||
|
|
||||||
var khrSurface = new KhrSurface(api.Context);
|
|
||||||
|
|
||||||
uint propertiesCount;
|
|
||||||
|
|
||||||
api.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, &propertiesCount, null);
|
|
||||||
|
|
||||||
var properties = new QueueFamilyProperties[propertiesCount];
|
|
||||||
|
|
||||||
fixed (QueueFamilyProperties* pProperties = properties)
|
|
||||||
{
|
|
||||||
api.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, &propertiesCount, pProperties);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint index = 0; index < propertiesCount; index++)
|
|
||||||
{
|
|
||||||
var queueFlags = properties[index].QueueFlags;
|
|
||||||
|
|
||||||
khrSurface.GetPhysicalDeviceSurfaceSupport(physicalDevice, index, surface, out var surfaceSupported)
|
|
||||||
.ThrowOnError();
|
|
||||||
|
|
||||||
if (queueFlags.HasFlag(RequiredFlags) && surfaceSupported)
|
|
||||||
{
|
|
||||||
queueCount = properties[index].QueueCount;
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
queueCount = 0;
|
|
||||||
return uint.MaxValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,70 +0,0 @@
|
|||||||
using Avalonia;
|
|
||||||
using Ryujinx.Ava.Ui.Vulkan.Surfaces;
|
|
||||||
using Ryujinx.Graphics.Vulkan;
|
|
||||||
using Silk.NET.Vulkan;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Vulkan
|
|
||||||
{
|
|
||||||
internal class VulkanPlatformInterface : IDisposable
|
|
||||||
{
|
|
||||||
private static VulkanOptions _options;
|
|
||||||
|
|
||||||
private VulkanPlatformInterface(VulkanInstance instance)
|
|
||||||
{
|
|
||||||
Instance = instance;
|
|
||||||
Api = instance.Api;
|
|
||||||
}
|
|
||||||
|
|
||||||
public VulkanPhysicalDevice PhysicalDevice { get; private set; }
|
|
||||||
public VulkanInstance Instance { get; }
|
|
||||||
public Vk Api { get; private set; }
|
|
||||||
public VulkanSurfaceRenderTarget MainSurface { get; set; }
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Instance?.Dispose();
|
|
||||||
Api?.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static VulkanPlatformInterface TryCreate()
|
|
||||||
{
|
|
||||||
_options = AvaloniaLocator.Current.GetService<VulkanOptions>() ?? new VulkanOptions();
|
|
||||||
|
|
||||||
var instance = VulkanInstance.Create(_options);
|
|
||||||
|
|
||||||
return new VulkanPlatformInterface(instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool TryInitialize()
|
|
||||||
{
|
|
||||||
var feature = TryCreate();
|
|
||||||
if (feature != null)
|
|
||||||
{
|
|
||||||
AvaloniaLocator.CurrentMutable.Bind<VulkanPlatformInterface>().ToConstant(feature);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public VulkanSurfaceRenderTarget CreateRenderTarget(IVulkanPlatformSurface platformSurface)
|
|
||||||
{
|
|
||||||
var surface = VulkanSurface.CreateSurface(Instance, platformSurface);
|
|
||||||
|
|
||||||
if (PhysicalDevice == null)
|
|
||||||
{
|
|
||||||
PhysicalDevice = VulkanPhysicalDevice.FindSuitablePhysicalDevice(Instance, surface, _options.PreferDiscreteGpu, _options.PreferredDevice);
|
|
||||||
}
|
|
||||||
|
|
||||||
var renderTarget = new VulkanSurfaceRenderTarget(this, surface);
|
|
||||||
|
|
||||||
if (MainSurface == null && surface != null)
|
|
||||||
{
|
|
||||||
MainSurface = renderTarget;
|
|
||||||
}
|
|
||||||
|
|
||||||
return renderTarget;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,18 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Silk.NET.Vulkan;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Vulkan
|
|
||||||
{
|
|
||||||
internal class VulkanQueue
|
|
||||||
{
|
|
||||||
public VulkanQueue(VulkanDevice device, Queue apiHandle)
|
|
||||||
{
|
|
||||||
Device = device;
|
|
||||||
InternalHandle = apiHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public VulkanDevice Device { get; }
|
|
||||||
public IntPtr Handle => InternalHandle.Handle;
|
|
||||||
internal Queue InternalHandle { get; }
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,32 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Silk.NET.Vulkan;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Vulkan
|
|
||||||
{
|
|
||||||
internal class VulkanSemaphorePair : IDisposable
|
|
||||||
{
|
|
||||||
private readonly VulkanDevice _device;
|
|
||||||
|
|
||||||
public unsafe VulkanSemaphorePair(VulkanDevice device)
|
|
||||||
{
|
|
||||||
_device = device;
|
|
||||||
|
|
||||||
var semaphoreCreateInfo = new SemaphoreCreateInfo { SType = StructureType.SemaphoreCreateInfo };
|
|
||||||
|
|
||||||
_device.Api.CreateSemaphore(_device.InternalHandle, semaphoreCreateInfo, null, out var semaphore).ThrowOnError();
|
|
||||||
ImageAvailableSemaphore = semaphore;
|
|
||||||
|
|
||||||
_device.Api.CreateSemaphore(_device.InternalHandle, semaphoreCreateInfo, null, out semaphore).ThrowOnError();
|
|
||||||
RenderFinishedSemaphore = semaphore;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Semaphore ImageAvailableSemaphore { get; }
|
|
||||||
internal Semaphore RenderFinishedSemaphore { get; }
|
|
||||||
|
|
||||||
public unsafe void Dispose()
|
|
||||||
{
|
|
||||||
_device.Api.DestroySemaphore(_device.InternalHandle, ImageAvailableSemaphore, null);
|
|
||||||
_device.Api.DestroySemaphore(_device.InternalHandle, RenderFinishedSemaphore, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,75 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Avalonia;
|
|
||||||
using Ryujinx.Ava.Ui.Vulkan.Surfaces;
|
|
||||||
using Silk.NET.Vulkan;
|
|
||||||
using Silk.NET.Vulkan.Extensions.KHR;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Vulkan
|
|
||||||
{
|
|
||||||
public class VulkanSurface : IDisposable
|
|
||||||
{
|
|
||||||
private readonly VulkanInstance _instance;
|
|
||||||
private readonly IVulkanPlatformSurface _vulkanPlatformSurface;
|
|
||||||
|
|
||||||
private VulkanSurface(IVulkanPlatformSurface vulkanPlatformSurface, VulkanInstance instance)
|
|
||||||
{
|
|
||||||
_vulkanPlatformSurface = vulkanPlatformSurface;
|
|
||||||
_instance = instance;
|
|
||||||
ApiHandle = vulkanPlatformSurface.CreateSurface(instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal SurfaceKHR ApiHandle { get; }
|
|
||||||
|
|
||||||
internal static KhrSurface SurfaceExtension { get; private set; }
|
|
||||||
|
|
||||||
internal PixelSize SurfaceSize => _vulkanPlatformSurface.SurfaceSize;
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
SurfaceExtension.DestroySurface(_instance.InternalHandle, ApiHandle, Span<AllocationCallbacks>.Empty);
|
|
||||||
_vulkanPlatformSurface.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static VulkanSurface CreateSurface(VulkanInstance instance, IVulkanPlatformSurface vulkanPlatformSurface)
|
|
||||||
{
|
|
||||||
if (SurfaceExtension == null)
|
|
||||||
{
|
|
||||||
instance.Api.TryGetInstanceExtension(instance.InternalHandle, out KhrSurface extension);
|
|
||||||
|
|
||||||
SurfaceExtension = extension;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new VulkanSurface(vulkanPlatformSurface, instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal bool CanSurfacePresent(VulkanPhysicalDevice physicalDevice)
|
|
||||||
{
|
|
||||||
SurfaceExtension.GetPhysicalDeviceSurfaceSupport(physicalDevice.InternalHandle, physicalDevice.QueueFamilyIndex, ApiHandle, out var isSupported);
|
|
||||||
|
|
||||||
return isSupported;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal SurfaceFormatKHR GetSurfaceFormat(VulkanPhysicalDevice physicalDevice)
|
|
||||||
{
|
|
||||||
Span<uint> surfaceFormatsCount = stackalloc uint[1];
|
|
||||||
SurfaceExtension.GetPhysicalDeviceSurfaceFormats(physicalDevice.InternalHandle, ApiHandle, surfaceFormatsCount, Span<SurfaceFormatKHR>.Empty);
|
|
||||||
Span<SurfaceFormatKHR> surfaceFormats = stackalloc SurfaceFormatKHR[(int)surfaceFormatsCount[0]];
|
|
||||||
SurfaceExtension.GetPhysicalDeviceSurfaceFormats(physicalDevice.InternalHandle, ApiHandle, surfaceFormatsCount, surfaceFormats);
|
|
||||||
|
|
||||||
if (surfaceFormats.Length == 1 && surfaceFormats[0].Format == Format.Undefined)
|
|
||||||
{
|
|
||||||
return new SurfaceFormatKHR(Format.B8G8R8A8Unorm, ColorSpaceKHR.ColorspaceSrgbNonlinearKhr);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var format in surfaceFormats)
|
|
||||||
{
|
|
||||||
if (format.Format == Format.B8G8R8A8Unorm && format.ColorSpace == ColorSpaceKHR.ColorspaceSrgbNonlinearKhr)
|
|
||||||
{
|
|
||||||
return format;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return surfaceFormats[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,43 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Avalonia;
|
|
||||||
using Ryujinx.Ava.Ui.Vulkan.Surfaces;
|
|
||||||
using Silk.NET.Vulkan;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Vulkan
|
|
||||||
{
|
|
||||||
internal class VulkanSurfaceRenderingSession : IDisposable
|
|
||||||
{
|
|
||||||
private readonly VulkanDevice _device;
|
|
||||||
private readonly VulkanSurfaceRenderTarget _renderTarget;
|
|
||||||
|
|
||||||
public VulkanSurfaceRenderingSession(VulkanDisplay display, VulkanDevice device,
|
|
||||||
VulkanSurfaceRenderTarget renderTarget, float scaling)
|
|
||||||
{
|
|
||||||
Display = display;
|
|
||||||
_device = device;
|
|
||||||
_renderTarget = renderTarget;
|
|
||||||
Scaling = scaling;
|
|
||||||
Begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
public VulkanDisplay Display { get; }
|
|
||||||
|
|
||||||
public PixelSize Size => _renderTarget.Size;
|
|
||||||
public Vk Api => _device.Api;
|
|
||||||
|
|
||||||
public float Scaling { get; }
|
|
||||||
|
|
||||||
private void Begin()
|
|
||||||
{
|
|
||||||
if (!Display.EnsureSwapchainAvailable())
|
|
||||||
{
|
|
||||||
_renderTarget.RecreateImage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_renderTarget.EndDraw();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,4 +1,8 @@
|
|||||||
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Controls.ApplicationLifetimes;
|
||||||
|
using Avalonia.Controls.Primitives;
|
||||||
|
using Avalonia.Media;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using FluentAvalonia.UI.Controls;
|
using FluentAvalonia.UI.Controls;
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
@@ -27,9 +31,69 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
{
|
{
|
||||||
UserResult result = UserResult.None;
|
UserResult result = UserResult.None;
|
||||||
|
|
||||||
ContentDialog contentDialog = new ContentDialog();
|
bool useOverlay = false;
|
||||||
|
Window mainWindow = null;
|
||||||
|
|
||||||
await ShowDialog();
|
if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime al)
|
||||||
|
{
|
||||||
|
foreach (var item in al.Windows)
|
||||||
|
{
|
||||||
|
if (item.IsActive && item is MainWindow window && window.ViewModel.IsGameRunning)
|
||||||
|
{
|
||||||
|
mainWindow = window;
|
||||||
|
useOverlay = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentDialog contentDialog = null;
|
||||||
|
ContentDialogOverlayWindow overlay = null;
|
||||||
|
|
||||||
|
if (useOverlay)
|
||||||
|
{
|
||||||
|
overlay = new ContentDialogOverlayWindow()
|
||||||
|
{
|
||||||
|
Height = mainWindow.Bounds.Height,
|
||||||
|
Width = mainWindow.Bounds.Width,
|
||||||
|
Position = mainWindow.PointToScreen(new Point())
|
||||||
|
};
|
||||||
|
|
||||||
|
mainWindow.PositionChanged += OverlayOnPositionChanged;
|
||||||
|
|
||||||
|
void OverlayOnPositionChanged(object sender, PixelPointEventArgs e)
|
||||||
|
{
|
||||||
|
overlay.Position = mainWindow.PointToScreen(new Point());
|
||||||
|
}
|
||||||
|
|
||||||
|
contentDialog = overlay.ContentDialog;
|
||||||
|
|
||||||
|
bool opened = false;
|
||||||
|
|
||||||
|
overlay.Opened += OverlayOnActivated;
|
||||||
|
|
||||||
|
async void OverlayOnActivated(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (opened)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
opened = true;
|
||||||
|
|
||||||
|
overlay.Position = mainWindow.PointToScreen(new Point());
|
||||||
|
|
||||||
|
await ShowDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
await overlay.ShowDialog(mainWindow);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
contentDialog = new ContentDialog();
|
||||||
|
|
||||||
|
await ShowDialog();
|
||||||
|
}
|
||||||
|
|
||||||
async Task ShowDialog()
|
async Task ShowDialog()
|
||||||
{
|
{
|
||||||
@@ -53,6 +117,14 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
});
|
});
|
||||||
|
|
||||||
await contentDialog.ShowAsync(ContentDialogPlacement.Popup);
|
await contentDialog.ShowAsync(ContentDialogPlacement.Popup);
|
||||||
|
|
||||||
|
overlay?.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (useOverlay)
|
||||||
|
{
|
||||||
|
overlay.Content = null;
|
||||||
|
overlay.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -323,4 +395,4 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
204
Ryujinx.Ava/Ui/Controls/EmbeddedWindow.cs
Normal file
204
Ryujinx.Ava/Ui/Controls/EmbeddedWindow.cs
Normal file
@@ -0,0 +1,204 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Input;
|
||||||
|
using Avalonia.Platform;
|
||||||
|
using SPB.Graphics;
|
||||||
|
using SPB.Platform;
|
||||||
|
using SPB.Platform.GLX;
|
||||||
|
using SPB.Platform.X11;
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using static Ryujinx.Ava.Ui.Controls.Win32NativeInterop;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.Ui.Controls
|
||||||
|
{
|
||||||
|
public unsafe class EmbeddedWindow : NativeControlHost
|
||||||
|
{
|
||||||
|
private WindowProc _wndProcDelegate;
|
||||||
|
private string _className;
|
||||||
|
|
||||||
|
protected GLXWindow X11Window { get; private set; }
|
||||||
|
protected IntPtr WindowHandle { get; set; }
|
||||||
|
protected IntPtr X11Display { get; set; }
|
||||||
|
|
||||||
|
public event EventHandler<IntPtr> WindowCreated;
|
||||||
|
public event EventHandler<Size> SizeChanged;
|
||||||
|
|
||||||
|
protected virtual void OnWindowDestroyed() { }
|
||||||
|
protected virtual void OnWindowDestroying()
|
||||||
|
{
|
||||||
|
WindowHandle = IntPtr.Zero;
|
||||||
|
X11Display = IntPtr.Zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EmbeddedWindow()
|
||||||
|
{
|
||||||
|
var stateObserverable = this.GetObservable(Control.BoundsProperty);
|
||||||
|
|
||||||
|
stateObserverable.Subscribe(StateChanged);
|
||||||
|
|
||||||
|
this.Initialized += NativeEmbeddedWindow_Initialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void OnWindowCreated() { }
|
||||||
|
|
||||||
|
private void NativeEmbeddedWindow_Initialized(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
OnWindowCreated();
|
||||||
|
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
WindowCreated?.Invoke(this, WindowHandle);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StateChanged(Rect rect)
|
||||||
|
{
|
||||||
|
SizeChanged?.Invoke(this, rect.Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IPlatformHandle CreateNativeControlCore(IPlatformHandle parent)
|
||||||
|
{
|
||||||
|
if (OperatingSystem.IsLinux())
|
||||||
|
{
|
||||||
|
return CreateLinux(parent);
|
||||||
|
}
|
||||||
|
else if (OperatingSystem.IsWindows())
|
||||||
|
{
|
||||||
|
return CreateWin32(parent);
|
||||||
|
}
|
||||||
|
return base.CreateNativeControlCore(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void DestroyNativeControlCore(IPlatformHandle control)
|
||||||
|
{
|
||||||
|
OnWindowDestroying();
|
||||||
|
|
||||||
|
if (OperatingSystem.IsLinux())
|
||||||
|
{
|
||||||
|
DestroyLinux();
|
||||||
|
}
|
||||||
|
else if (OperatingSystem.IsWindows())
|
||||||
|
{
|
||||||
|
DestroyWin32(control);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
base.DestroyNativeControlCore(control);
|
||||||
|
}
|
||||||
|
|
||||||
|
OnWindowDestroyed();
|
||||||
|
}
|
||||||
|
|
||||||
|
[SupportedOSPlatform("linux")]
|
||||||
|
IPlatformHandle CreateLinux(IPlatformHandle parent)
|
||||||
|
{
|
||||||
|
X11Window = PlatformHelper.CreateOpenGLWindow(FramebufferFormat.Default, 0, 0, 100, 100) as GLXWindow;
|
||||||
|
|
||||||
|
WindowHandle = X11Window.WindowHandle.RawHandle;
|
||||||
|
|
||||||
|
X11Display = X11Window.DisplayHandle.RawHandle;
|
||||||
|
|
||||||
|
return new PlatformHandle(WindowHandle, "X11");
|
||||||
|
}
|
||||||
|
|
||||||
|
[SupportedOSPlatform("windows")]
|
||||||
|
unsafe IPlatformHandle CreateWin32(IPlatformHandle parent)
|
||||||
|
{
|
||||||
|
_className = "NativeWindow-" + Guid.NewGuid();
|
||||||
|
_wndProcDelegate = WndProc;
|
||||||
|
var wndClassEx = new WNDCLASSEX
|
||||||
|
{
|
||||||
|
cbSize = Marshal.SizeOf<WNDCLASSEX>(),
|
||||||
|
hInstance = GetModuleHandle(null),
|
||||||
|
lpfnWndProc = _wndProcDelegate,
|
||||||
|
style = ClassStyles.CS_OWNDC,
|
||||||
|
lpszClassName = _className,
|
||||||
|
hCursor = LoadCursor(IntPtr.Zero, (IntPtr)Cursors.IDC_ARROW)
|
||||||
|
};
|
||||||
|
|
||||||
|
var atom = RegisterClassEx(ref wndClassEx);
|
||||||
|
|
||||||
|
var handle = CreateWindowEx(
|
||||||
|
0,
|
||||||
|
_className,
|
||||||
|
"NativeWindow",
|
||||||
|
WindowStyles.WS_CHILD,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
640,
|
||||||
|
480,
|
||||||
|
parent.Handle,
|
||||||
|
IntPtr.Zero,
|
||||||
|
IntPtr.Zero,
|
||||||
|
IntPtr.Zero);
|
||||||
|
|
||||||
|
WindowHandle = handle;
|
||||||
|
|
||||||
|
return new PlatformHandle(WindowHandle, "HWND");
|
||||||
|
}
|
||||||
|
|
||||||
|
[SupportedOSPlatform("windows")]
|
||||||
|
internal IntPtr WndProc(IntPtr hWnd, WindowsMessages msg, IntPtr wParam, IntPtr lParam)
|
||||||
|
{
|
||||||
|
var point = new Point((long)lParam & 0xFFFF, ((long)lParam >> 16) & 0xFFFF);
|
||||||
|
var root = VisualRoot as Window;
|
||||||
|
bool isLeft = false;
|
||||||
|
switch (msg)
|
||||||
|
{
|
||||||
|
case WindowsMessages.LBUTTONDOWN:
|
||||||
|
case WindowsMessages.RBUTTONDOWN:
|
||||||
|
isLeft = msg == WindowsMessages.LBUTTONDOWN;
|
||||||
|
this.RaiseEvent(new PointerPressedEventArgs(
|
||||||
|
this,
|
||||||
|
new Avalonia.Input.Pointer(0, PointerType.Mouse, true),
|
||||||
|
root,
|
||||||
|
this.TranslatePoint(point, root).Value,
|
||||||
|
(ulong)Environment.TickCount64,
|
||||||
|
new PointerPointProperties(isLeft ? RawInputModifiers.LeftMouseButton : RawInputModifiers.RightMouseButton, isLeft ? PointerUpdateKind.LeftButtonPressed : PointerUpdateKind.RightButtonPressed),
|
||||||
|
KeyModifiers.None));
|
||||||
|
break;
|
||||||
|
case WindowsMessages.LBUTTONUP:
|
||||||
|
case WindowsMessages.RBUTTONUP:
|
||||||
|
isLeft = msg == WindowsMessages.LBUTTONUP;
|
||||||
|
this.RaiseEvent(new PointerReleasedEventArgs(
|
||||||
|
this,
|
||||||
|
new Avalonia.Input.Pointer(0, PointerType.Mouse, true),
|
||||||
|
root,
|
||||||
|
this.TranslatePoint(point, root).Value,
|
||||||
|
(ulong)Environment.TickCount64,
|
||||||
|
new PointerPointProperties(isLeft ? RawInputModifiers.LeftMouseButton : RawInputModifiers.RightMouseButton, isLeft ? PointerUpdateKind.LeftButtonReleased : PointerUpdateKind.RightButtonReleased),
|
||||||
|
KeyModifiers.None,
|
||||||
|
isLeft ? MouseButton.Left : MouseButton.Right));
|
||||||
|
break;
|
||||||
|
case WindowsMessages.MOUSEMOVE:
|
||||||
|
this.RaiseEvent(new PointerEventArgs(
|
||||||
|
PointerMovedEvent,
|
||||||
|
this,
|
||||||
|
new Avalonia.Input.Pointer(0, PointerType.Mouse, true),
|
||||||
|
root,
|
||||||
|
this.TranslatePoint(point, root).Value,
|
||||||
|
(ulong)Environment.TickCount64,
|
||||||
|
new PointerPointProperties(RawInputModifiers.None, PointerUpdateKind.Other),
|
||||||
|
KeyModifiers.None));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return DefWindowProc(hWnd, msg, (IntPtr)wParam, (IntPtr)lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DestroyLinux()
|
||||||
|
{
|
||||||
|
X11Window?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
[SupportedOSPlatform("windows")]
|
||||||
|
void DestroyWin32(IPlatformHandle handle)
|
||||||
|
{
|
||||||
|
DestroyWindow(handle.Handle);
|
||||||
|
UnregisterClass(_className, GetModuleHandle(null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
85
Ryujinx.Ava/Ui/Controls/OpenGLEmbeddedWindow.cs
Normal file
85
Ryujinx.Ava/Ui/Controls/OpenGLEmbeddedWindow.cs
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.OpenGL;
|
||||||
|
using OpenTK.Graphics.OpenGL;
|
||||||
|
using Ryujinx.Common.Configuration;
|
||||||
|
using SPB.Graphics;
|
||||||
|
using SPB.Graphics.OpenGL;
|
||||||
|
using SPB.Platform;
|
||||||
|
using SPB.Platform.GLX;
|
||||||
|
using SPB.Platform.WGL;
|
||||||
|
using SPB.Windowing;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.Ui.Controls
|
||||||
|
{
|
||||||
|
public class OpenGLEmbeddedWindow : EmbeddedWindow
|
||||||
|
{
|
||||||
|
private readonly int _major;
|
||||||
|
private readonly int _minor;
|
||||||
|
private readonly GraphicsDebugLevel _graphicsDebugLevel;
|
||||||
|
private SwappableNativeWindowBase _window;
|
||||||
|
public OpenGLContextBase Context { get; set; }
|
||||||
|
|
||||||
|
public OpenGLEmbeddedWindow(int major, int minor, GraphicsDebugLevel graphicsDebugLevel)
|
||||||
|
{
|
||||||
|
_major = major;
|
||||||
|
_minor = minor;
|
||||||
|
_graphicsDebugLevel = graphicsDebugLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnWindowDestroying()
|
||||||
|
{
|
||||||
|
Context.Dispose();
|
||||||
|
base.OnWindowDestroying();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnWindowCreated()
|
||||||
|
{
|
||||||
|
base.OnWindowCreated();
|
||||||
|
|
||||||
|
if (OperatingSystem.IsWindows())
|
||||||
|
{
|
||||||
|
_window = new WGLWindow(new NativeHandle(WindowHandle));
|
||||||
|
}
|
||||||
|
else if (OperatingSystem.IsLinux())
|
||||||
|
{
|
||||||
|
_window = X11Window;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new PlatformNotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
var flags = OpenGLContextFlags.Compat;
|
||||||
|
if (_graphicsDebugLevel != GraphicsDebugLevel.None)
|
||||||
|
{
|
||||||
|
flags |= OpenGLContextFlags.Debug;
|
||||||
|
}
|
||||||
|
|
||||||
|
Context = PlatformHelper.CreateOpenGLContext(FramebufferFormat.Default, _major, _minor, flags);
|
||||||
|
|
||||||
|
Context.Initialize(_window);
|
||||||
|
Context.MakeCurrent(_window);
|
||||||
|
|
||||||
|
var bindingsContext = new OpenToolkitBindingsContext(Context.GetProcAddress);
|
||||||
|
|
||||||
|
GL.LoadBindings(bindingsContext);
|
||||||
|
Context.MakeCurrent(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void MakeCurrent()
|
||||||
|
{
|
||||||
|
Context.MakeCurrent(_window);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void MakeCurrent(NativeWindowBase window)
|
||||||
|
{
|
||||||
|
Context.MakeCurrent(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SwapBuffers()
|
||||||
|
{
|
||||||
|
_window.SwapBuffers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user