Compare commits
20 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
2492e7e808 | ||
|
36172ab43b | ||
|
4d69286a9c | ||
|
1529e6cf0d | ||
|
f468db7602 | ||
|
c5f1d1749a | ||
|
7dd69f2d0e | ||
|
c646638680 | ||
|
65f2a82b97 | ||
|
93dd6d525a | ||
|
96d4ad952c | ||
|
6a07f80b76 | ||
|
22214ac664 | ||
|
45e520a27c | ||
|
5b5810a46a | ||
|
619ac86bd0 | ||
|
7a1ab71c73 | ||
|
dc4ba3993b | ||
|
81f1a4dc31 | ||
|
c64524a240 |
@@ -251,6 +251,13 @@ namespace ARMeilleure.Decoders
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Compare and branch instructions are always conditional.
|
||||||
|
if (opCode.Instruction.Name == InstName.Cbz ||
|
||||||
|
opCode.Instruction.Name == InstName.Cbnz)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Note: On ARM32, most instructions have conditional execution,
|
// Note: On ARM32, most instructions have conditional execution,
|
||||||
// so there's no "Always" (unconditional) branch like on ARM64.
|
// so there's no "Always" (unconditional) branch like on ARM64.
|
||||||
// We need to check if the condition is "Always" instead.
|
// We need to check if the condition is "Always" instead.
|
||||||
|
@@ -151,7 +151,7 @@ namespace ARMeilleure.Decoders
|
|||||||
|
|
||||||
public static bool VectorArgumentsInvalid(bool q, params int[] args)
|
public static bool VectorArgumentsInvalid(bool q, params int[] args)
|
||||||
{
|
{
|
||||||
if (q)
|
if (q)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < args.Length; i++)
|
for (int i = 0; i < args.Length; i++)
|
||||||
{
|
{
|
||||||
|
@@ -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; }
|
||||||
|
}
|
||||||
|
}
|
@@ -3,6 +3,7 @@ namespace ARMeilleure.Decoders
|
|||||||
interface IOpCode32Mem : IOpCode32
|
interface IOpCode32Mem : IOpCode32
|
||||||
{
|
{
|
||||||
int Rt { get; }
|
int Rt { get; }
|
||||||
|
int Rt2 => Rt | 1;
|
||||||
int Rn { get; }
|
int Rn { get; }
|
||||||
|
|
||||||
bool WBack { get; }
|
bool WBack { 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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;
|
||||||
|
|
||||||
|
@@ -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)
|
||||||
{
|
{
|
||||||
|
@@ -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;
|
||||||
|
@@ -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;
|
||||||
|
@@ -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;
|
||||||
|
|
||||||
|
@@ -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)
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
@@ -8,6 +8,7 @@ namespace ARMeilleure.Decoders
|
|||||||
{
|
{
|
||||||
Cond = Condition.Al;
|
Cond = Condition.Al;
|
||||||
|
|
||||||
|
IsThumb = true;
|
||||||
OpCodeSizeInBytes = 2;
|
OpCodeSizeInBytes = 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -4,14 +4,13 @@ namespace ARMeilleure.Decoders
|
|||||||
{
|
{
|
||||||
public int Rd { get; }
|
public int Rd { get; }
|
||||||
|
|
||||||
public bool Add => true;
|
|
||||||
public int Immediate { get; }
|
public int Immediate { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16Adr(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16Adr(inst, address, opCode);
|
||||||
|
|
||||||
public OpCodeT16Adr(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCodeT16Adr(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
Rd = (opCode >> 8) & 7;
|
Rd = (opCode >> 8) & 7;
|
||||||
|
|
||||||
int imm = (opCode & 0xff) << 2;
|
int imm = (opCode & 0xff) << 2;
|
||||||
Immediate = (int)(GetPc() & 0xfffffffc) + imm;
|
Immediate = (int)(GetPc() & 0xfffffffc) + imm;
|
||||||
|
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
ARMeilleure/Decoders/OpCodeT32AluImm12.cs
Normal file
16
ARMeilleure/Decoders/OpCodeT32AluImm12.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT32AluImm12 : OpCodeT32Alu, IOpCode32AluImm
|
||||||
|
{
|
||||||
|
public int Immediate { get; }
|
||||||
|
|
||||||
|
public bool IsRotated => false;
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32AluImm12(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT32AluImm12(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Immediate = (opCode & 0xff) | ((opCode >> 4) & 0x700) | ((opCode >> 15) & 0x800);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
ARMeilleure/Decoders/OpCodeT32AluReg.cs
Normal file
14
ARMeilleure/Decoders/OpCodeT32AluReg.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT32AluReg : OpCodeT32Alu, IOpCode32AluReg
|
||||||
|
{
|
||||||
|
public int Rm { get; }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32AluReg(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT32AluReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rm = (opCode >> 0) & 0xf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
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;
|
||||||
}
|
}
|
||||||
|
@@ -23,7 +23,7 @@ namespace ARMeilleure.Decoders
|
|||||||
Add = ((opCode >> 23) & 1) != 0;
|
Add = ((opCode >> 23) & 1) != 0;
|
||||||
WBack = ((opCode >> 21) & 1) != 0;
|
WBack = ((opCode >> 21) & 1) != 0;
|
||||||
|
|
||||||
Immediate = opCode & 0xff;
|
Immediate = (opCode & 0xff) << 2;
|
||||||
|
|
||||||
IsLoad = ((opCode >> 20) & 1) != 0;
|
IsLoad = ((opCode >> 20) & 1) != 0;
|
||||||
}
|
}
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
16
ARMeilleure/Decoders/OpCodeT32MovImm16.cs
Normal file
16
ARMeilleure/Decoders/OpCodeT32MovImm16.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT32MovImm16 : OpCodeT32Alu, IOpCode32AluImm16
|
||||||
|
{
|
||||||
|
public int Immediate { get; }
|
||||||
|
|
||||||
|
public bool IsRotated => false;
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32MovImm16(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT32MovImm16(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Immediate = (opCode & 0xff) | ((opCode >> 4) & 0x700) | ((opCode >> 15) & 0x800) | ((opCode >> 4) & 0xf000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
ARMeilleure/Decoders/OpCodeT32ShiftReg.cs
Normal file
19
ARMeilleure/Decoders/OpCodeT32ShiftReg.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT32ShiftReg : OpCodeT32Alu, IOpCode32AluRsReg
|
||||||
|
{
|
||||||
|
public int Rm => Rn;
|
||||||
|
public int Rs { get; }
|
||||||
|
|
||||||
|
public ShiftType ShiftType { get; }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32ShiftReg(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT32ShiftReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rs = (opCode >> 0) & 0xf;
|
||||||
|
|
||||||
|
ShiftType = (ShiftType)((opCode >> 21) & 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
ARMeilleure/Decoders/OpCodeT32Tb.cs
Normal file
16
ARMeilleure/Decoders/OpCodeT32Tb.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT32Tb : OpCodeT32, IOpCode32BReg
|
||||||
|
{
|
||||||
|
public int Rm { get; }
|
||||||
|
public int Rn { get; }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32Tb(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT32Tb(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rm = (opCode >> 0) & 0xf;
|
||||||
|
Rn = (opCode >> 16) & 0xf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -792,7 +792,61 @@ namespace ARMeilleure.Decoders
|
|||||||
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);
|
||||||
|
|
||||||
// FP & SIMD
|
// VFP
|
||||||
|
SetVfp("<<<<11101x110000xxxx101x11x0xxxx", InstName.Vabs, InstEmit32.Vabs_S, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
|
||||||
|
SetVfp("<<<<11100x11xxxxxxxx101xx0x0xxxx", InstName.Vadd, InstEmit32.Vadd_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
|
SetVfp("<<<<11101x11010xxxxx101x01x0xxxx", InstName.Vcmp, InstEmit32.Vcmp, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
|
||||||
|
SetVfp("<<<<11101x11010xxxxx101x11x0xxxx", InstName.Vcmpe, InstEmit32.Vcmpe, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
|
||||||
|
SetVfp("<<<<11101x110111xxxx101x11x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FD, OpCode32SimdS.Create, OpCode32SimdS.CreateT32); // FP 32 and 64, scalar.
|
||||||
|
SetVfp("<<<<11101x11110xxxxx101x11x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FI, OpCode32SimdCvtFI.Create, OpCode32SimdCvtFI.CreateT32); // FP32 to int.
|
||||||
|
SetVfp("<<<<11101x111000xxxx101xx1x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FI, OpCode32SimdCvtFI.Create, OpCode32SimdCvtFI.CreateT32); // Int to FP32.
|
||||||
|
SetVfp("111111101x1111xxxxxx101xx1x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_RM, OpCode32SimdCvtFI.Create, OpCode32SimdCvtFI.CreateT32); // The many FP32 to int encodings (fp).
|
||||||
|
SetVfp("<<<<11101x00xxxxxxxx101xx0x0xxxx", InstName.Vdiv, InstEmit32.Vdiv_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
|
SetVfp("<<<<11101xx0xxxxxxxx1011x0x10000", InstName.Vdup, InstEmit32.Vdup, OpCode32SimdDupGP.Create, OpCode32SimdDupGP.CreateT32);
|
||||||
|
SetVfp("<<<<11101x10xxxxxxxx101xx0x0xxxx", InstName.Vfma, InstEmit32.Vfma_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
|
SetVfp("<<<<11101x10xxxxxxxx101xx1x0xxxx", InstName.Vfms, InstEmit32.Vfms_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
|
SetVfp("<<<<11101x01xxxxxxxx101xx1x0xxxx", InstName.Vfnma, InstEmit32.Vfnma_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
|
SetVfp("<<<<11101x01xxxxxxxx101xx0x0xxxx", InstName.Vfnms, InstEmit32.Vfnms_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
|
SetVfp("<<<<11001x01xxxxxxxx1011xxxxxxx0", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create, OpCode32SimdMemMult.CreateT32);
|
||||||
|
SetVfp("<<<<11001x11xxxxxxxx1011xxxxxxx0", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create, OpCode32SimdMemMult.CreateT32);
|
||||||
|
SetVfp("<<<<11010x11xxxxxxxx1011xxxxxxx0", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create, OpCode32SimdMemMult.CreateT32);
|
||||||
|
SetVfp("<<<<11001x01xxxxxxxx1010xxxxxxxx", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create, OpCode32SimdMemMult.CreateT32);
|
||||||
|
SetVfp("<<<<11001x11xxxxxxxx1010xxxxxxxx", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create, OpCode32SimdMemMult.CreateT32);
|
||||||
|
SetVfp("<<<<11010x11xxxxxxxx1010xxxxxxxx", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create, OpCode32SimdMemMult.CreateT32);
|
||||||
|
SetVfp("<<<<1101xx01xxxxxxxx101xxxxxxxxx", InstName.Vldr, InstEmit32.Vldr, OpCode32SimdMemImm.Create, OpCode32SimdMemImm.CreateT32);
|
||||||
|
SetVfp("111111101x00xxxxxxxx10>>x0x0xxxx", InstName.Vmaxnm, InstEmit32.Vmaxnm_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
|
SetVfp("111111101x00xxxxxxxx10>>x1x0xxxx", InstName.Vminnm, InstEmit32.Vminnm_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
|
SetVfp("<<<<11100x00xxxxxxxx101xx0x0xxxx", InstName.Vmla, InstEmit32.Vmla_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
|
SetVfp("<<<<11100x00xxxxxxxx101xx1x0xxxx", InstName.Vmls, InstEmit32.Vmls_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
|
SetVfp("<<<<11100xx0xxxxxxxx1011xxx10000", InstName.Vmov, InstEmit32.Vmov_G1, OpCode32SimdMovGpElem.Create, OpCode32SimdMovGpElem.CreateT32); // From gen purpose.
|
||||||
|
SetVfp("<<<<1110xxx1xxxxxxxx1011xxx10000", InstName.Vmov, InstEmit32.Vmov_G1, OpCode32SimdMovGpElem.Create, OpCode32SimdMovGpElem.CreateT32); // To gen purpose.
|
||||||
|
SetVfp("<<<<1100010xxxxxxxxx101000x1xxxx", InstName.Vmov, InstEmit32.Vmov_G2, OpCode32SimdMovGpDouble.Create, OpCode32SimdMovGpDouble.CreateT32); // To/from gen purpose x2 and single precision x2.
|
||||||
|
SetVfp("<<<<1100010xxxxxxxxx101100x1xxxx", InstName.Vmov, InstEmit32.Vmov_GD, OpCode32SimdMovGpDouble.Create, OpCode32SimdMovGpDouble.CreateT32); // To/from gen purpose x2 and double precision.
|
||||||
|
SetVfp("<<<<1110000xxxxxxxxx1010x0010000", InstName.Vmov, InstEmit32.Vmov_GS, OpCode32SimdMovGp.Create, OpCode32SimdMovGp.CreateT32); // To/from gen purpose and single precision.
|
||||||
|
SetVfp("<<<<11101x11xxxxxxxx101x0000xxxx", InstName.Vmov, InstEmit32.Vmov_I, OpCode32SimdImm44.Create, OpCode32SimdImm44.CreateT32); // Scalar f16/32/64 based on size 01 10 11.
|
||||||
|
SetVfp("<<<<11101x110000xxxx101x01x0xxxx", InstName.Vmov, InstEmit32.Vmov_S, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
|
||||||
|
SetVfp("<<<<11101111xxxxxxxx101000010000", InstName.Vmrs, InstEmit32.Vmrs, OpCode32SimdSpecial.Create, OpCode32SimdSpecial.CreateT32);
|
||||||
|
SetVfp("<<<<11101110xxxxxxxx101000010000", InstName.Vmsr, InstEmit32.Vmsr, OpCode32SimdSpecial.Create, OpCode32SimdSpecial.CreateT32);
|
||||||
|
SetVfp("<<<<11100x10xxxxxxxx101xx0x0xxxx", InstName.Vmul, InstEmit32.Vmul_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
|
SetVfp("<<<<11101x110001xxxx101x01x0xxxx", InstName.Vneg, InstEmit32.Vneg_S, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
|
||||||
|
SetVfp("<<<<11100x01xxxxxxxx101xx1x0xxxx", InstName.Vnmla, InstEmit32.Vnmla_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
|
SetVfp("<<<<11100x01xxxxxxxx101xx0x0xxxx", InstName.Vnmls, InstEmit32.Vnmls_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
|
SetVfp("<<<<11100x10xxxxxxxx101xx1x0xxxx", InstName.Vnmul, InstEmit32.Vnmul_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
|
SetVfp("111111101x1110xxxxxx101x01x0xxxx", InstName.Vrint, InstEmit32.Vrint_RM, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
|
||||||
|
SetVfp("<<<<11101x110110xxxx101x11x0xxxx", InstName.Vrint, InstEmit32.Vrint_Z, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
|
||||||
|
SetVfp("<<<<11101x110111xxxx101x01x0xxxx", InstName.Vrintx, InstEmit32.Vrintx_S, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
|
||||||
|
SetVfp("<<<<11101x110001xxxx101x11x0xxxx", InstName.Vsqrt, InstEmit32.Vsqrt_S, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
|
||||||
|
SetVfp("111111100xxxxxxxxxxx101xx0x0xxxx", InstName.Vsel, InstEmit32.Vsel, OpCode32SimdSel.Create, OpCode32SimdSel.CreateT32);
|
||||||
|
SetVfp("<<<<11001x00xxxxxxxx1011xxxxxxx0", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create, OpCode32SimdMemMult.CreateT32);
|
||||||
|
SetVfp("<<<<11001x10xxxxxxxx1011xxxxxxx0", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create, OpCode32SimdMemMult.CreateT32);
|
||||||
|
SetVfp("<<<<11010x10xxxxxxxx1011xxxxxxx0", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create, OpCode32SimdMemMult.CreateT32);
|
||||||
|
SetVfp("<<<<11001x00xxxxxxxx1010xxxxxxxx", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create, OpCode32SimdMemMult.CreateT32);
|
||||||
|
SetVfp("<<<<11001x10xxxxxxxx1010xxxxxxxx", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create, OpCode32SimdMemMult.CreateT32);
|
||||||
|
SetVfp("<<<<11010x10xxxxxxxx1010xxxxxxxx", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create, OpCode32SimdMemMult.CreateT32);
|
||||||
|
SetVfp("<<<<1101xx00xxxxxxxx101xxxxxxxxx", InstName.Vstr, InstEmit32.Vstr, OpCode32SimdMemImm.Create, OpCode32SimdMemImm.CreateT32);
|
||||||
|
SetVfp("<<<<11100x11xxxxxxxx101xx1x0xxxx", InstName.Vsub, InstEmit32.Vsub_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
|
|
||||||
|
// ASIMD
|
||||||
SetA32("111100111x110000xxx0001101x0xxx0", InstName.Aesd_V, InstEmit32.Aesd_V, OpCode32Simd.Create);
|
SetA32("111100111x110000xxx0001101x0xxx0", InstName.Aesd_V, InstEmit32.Aesd_V, OpCode32Simd.Create);
|
||||||
SetA32("111100111x110000xxx0001100x0xxx0", InstName.Aese_V, InstEmit32.Aese_V, OpCode32Simd.Create);
|
SetA32("111100111x110000xxx0001100x0xxx0", InstName.Aese_V, InstEmit32.Aese_V, OpCode32Simd.Create);
|
||||||
SetA32("111100111x110000xxx0001111x0xxx0", InstName.Aesimc_V, InstEmit32.Aesimc_V, OpCode32Simd.Create);
|
SetA32("111100111x110000xxx0001111x0xxx0", InstName.Aesimc_V, InstEmit32.Aesimc_V, OpCode32Simd.Create);
|
||||||
@@ -803,11 +857,9 @@ namespace ARMeilleure.Decoders
|
|||||||
SetA32("111100110x10xxx0xxx01100x1x0xxx0", InstName.Sha256su1_V, InstEmit32.Sha256su1_V, OpCode32SimdReg.Create);
|
SetA32("111100110x10xxx0xxx01100x1x0xxx0", InstName.Sha256su1_V, InstEmit32.Sha256su1_V, OpCode32SimdReg.Create);
|
||||||
SetA32("1111001x0x<<xxxxxxxx0111xxx0xxxx", InstName.Vabd, InstEmit32.Vabd_I, OpCode32SimdReg.Create);
|
SetA32("1111001x0x<<xxxxxxxx0111xxx0xxxx", InstName.Vabd, InstEmit32.Vabd_I, OpCode32SimdReg.Create);
|
||||||
SetA32("1111001x1x<<xxxxxxxx0111x0x0xxxx", InstName.Vabdl, InstEmit32.Vabdl_I, OpCode32SimdRegLong.Create);
|
SetA32("1111001x1x<<xxxxxxxx0111x0x0xxxx", InstName.Vabdl, InstEmit32.Vabdl_I, OpCode32SimdRegLong.Create);
|
||||||
SetA32("<<<<11101x110000xxxx101x11x0xxxx", InstName.Vabs, InstEmit32.Vabs_S, OpCode32SimdS.Create);
|
|
||||||
SetA32("111100111x11<<01xxxx00110xx0xxxx", InstName.Vabs, InstEmit32.Vabs_V, OpCode32SimdCmpZ.Create);
|
SetA32("111100111x11<<01xxxx00110xx0xxxx", InstName.Vabs, InstEmit32.Vabs_V, OpCode32SimdCmpZ.Create);
|
||||||
SetA32("111100111x111001xxxx01110xx0xxxx", InstName.Vabs, InstEmit32.Vabs_V, OpCode32SimdCmpZ.Create);
|
SetA32("111100111x111001xxxx01110xx0xxxx", InstName.Vabs, InstEmit32.Vabs_V, OpCode32SimdCmpZ.Create);
|
||||||
SetA32("111100100xxxxxxxxxxx1000xxx0xxxx", InstName.Vadd, InstEmit32.Vadd_I, OpCode32SimdReg.Create);
|
SetA32("111100100xxxxxxxxxxx1000xxx0xxxx", InstName.Vadd, InstEmit32.Vadd_I, OpCode32SimdReg.Create);
|
||||||
SetA32("<<<<11100x11xxxxxxxx101xx0x0xxxx", InstName.Vadd, InstEmit32.Vadd_S, OpCode32SimdRegS.Create);
|
|
||||||
SetA32("111100100x00xxxxxxxx1101xxx0xxxx", InstName.Vadd, InstEmit32.Vadd_V, OpCode32SimdReg.Create);
|
SetA32("111100100x00xxxxxxxx1101xxx0xxxx", InstName.Vadd, InstEmit32.Vadd_V, OpCode32SimdReg.Create);
|
||||||
SetA32("1111001x1x<<xxxxxxx00000x0x0xxxx", InstName.Vaddl, InstEmit32.Vaddl_I, OpCode32SimdRegLong.Create);
|
SetA32("1111001x1x<<xxxxxxx00000x0x0xxxx", InstName.Vaddl, InstEmit32.Vaddl_I, OpCode32SimdRegLong.Create);
|
||||||
SetA32("1111001x1x<<xxxxxxx00001x0x0xxxx", InstName.Vaddw, InstEmit32.Vaddw_I, OpCode32SimdRegWide.Create);
|
SetA32("1111001x1x<<xxxxxxx00001x0x0xxxx", InstName.Vaddw, InstEmit32.Vaddw_I, OpCode32SimdRegWide.Create);
|
||||||
@@ -828,25 +880,13 @@ namespace ARMeilleure.Decoders
|
|||||||
SetA32("111100111x11xx01xxxx0x000xx0xxxx", InstName.Vcgt, InstEmit32.Vcgt_Z, OpCode32SimdCmpZ.Create);
|
SetA32("111100111x11xx01xxxx0x000xx0xxxx", InstName.Vcgt, InstEmit32.Vcgt_Z, OpCode32SimdCmpZ.Create);
|
||||||
SetA32("111100111x11xx01xxxx0x011xx0xxxx", InstName.Vcle, InstEmit32.Vcle_Z, OpCode32SimdCmpZ.Create);
|
SetA32("111100111x11xx01xxxx0x011xx0xxxx", InstName.Vcle, InstEmit32.Vcle_Z, OpCode32SimdCmpZ.Create);
|
||||||
SetA32("111100111x11xx01xxxx0x100xx0xxxx", InstName.Vclt, InstEmit32.Vclt_Z, OpCode32SimdCmpZ.Create);
|
SetA32("111100111x11xx01xxxx0x100xx0xxxx", InstName.Vclt, InstEmit32.Vclt_Z, OpCode32SimdCmpZ.Create);
|
||||||
SetA32("<<<<11101x11010xxxxx101x01x0xxxx", InstName.Vcmp, InstEmit32.Vcmp, OpCode32SimdS.Create);
|
|
||||||
SetA32("<<<<11101x11010xxxxx101x11x0xxxx", InstName.Vcmpe, InstEmit32.Vcmpe, OpCode32SimdS.Create);
|
|
||||||
SetA32("111100111x110000xxxx01010xx0xxxx", InstName.Vcnt, InstEmit32.Vcnt, OpCode32SimdCmpZ.Create);
|
SetA32("111100111x110000xxxx01010xx0xxxx", InstName.Vcnt, InstEmit32.Vcnt, OpCode32SimdCmpZ.Create);
|
||||||
SetA32("<<<<11101x110111xxxx101x11x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FD, OpCode32SimdS.Create); // FP 32 and 64, scalar.
|
|
||||||
SetA32("<<<<11101x11110xxxxx101x11x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FI, OpCode32SimdCvtFI.Create); // FP32 to int.
|
|
||||||
SetA32("<<<<11101x111000xxxx101xx1x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FI, OpCode32SimdCvtFI.Create); // Int to FP32.
|
|
||||||
SetA32("111111101x1111xxxxxx101xx1x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_RM, OpCode32SimdCvtFI.Create); // The many FP32 to int encodings (fp).
|
|
||||||
SetA32("111100111x111011xxxx011xxxx0xxxx", InstName.Vcvt, InstEmit32.Vcvt_V, OpCode32SimdCmpZ.Create); // FP and integer, vector.
|
SetA32("111100111x111011xxxx011xxxx0xxxx", InstName.Vcvt, InstEmit32.Vcvt_V, OpCode32SimdCmpZ.Create); // FP and integer, vector.
|
||||||
SetA32("<<<<11101x00xxxxxxxx101xx0x0xxxx", InstName.Vdiv, InstEmit32.Vdiv_S, OpCode32SimdRegS.Create);
|
|
||||||
SetA32("<<<<11101xx0xxxxxxxx1011x0x10000", InstName.Vdup, InstEmit32.Vdup, OpCode32SimdDupGP.Create);
|
|
||||||
SetA32("111100111x11xxxxxxxx11000xx0xxxx", InstName.Vdup, InstEmit32.Vdup_1, OpCode32SimdDupElem.Create);
|
SetA32("111100111x11xxxxxxxx11000xx0xxxx", InstName.Vdup, InstEmit32.Vdup_1, OpCode32SimdDupElem.Create);
|
||||||
SetA32("111100110x00xxxxxxxx0001xxx1xxxx", InstName.Veor, InstEmit32.Veor_I, OpCode32SimdBinary.Create);
|
SetA32("111100110x00xxxxxxxx0001xxx1xxxx", InstName.Veor, InstEmit32.Veor_I, OpCode32SimdBinary.Create);
|
||||||
SetA32("111100101x11xxxxxxxxxxxxxxx0xxxx", InstName.Vext, InstEmit32.Vext, OpCode32SimdExt.Create);
|
SetA32("111100101x11xxxxxxxxxxxxxxx0xxxx", InstName.Vext, InstEmit32.Vext, OpCode32SimdExt.Create);
|
||||||
SetA32("<<<<11101x10xxxxxxxx101xx0x0xxxx", InstName.Vfma, InstEmit32.Vfma_S, OpCode32SimdRegS.Create);
|
|
||||||
SetA32("111100100x00xxxxxxxx1100xxx1xxxx", InstName.Vfma, InstEmit32.Vfma_V, OpCode32SimdReg.Create);
|
SetA32("111100100x00xxxxxxxx1100xxx1xxxx", InstName.Vfma, InstEmit32.Vfma_V, OpCode32SimdReg.Create);
|
||||||
SetA32("<<<<11101x10xxxxxxxx101xx1x0xxxx", InstName.Vfms, InstEmit32.Vfms_S, OpCode32SimdRegS.Create);
|
|
||||||
SetA32("111100100x10xxxxxxxx1100xxx1xxxx", InstName.Vfms, InstEmit32.Vfms_V, OpCode32SimdReg.Create);
|
SetA32("111100100x10xxxxxxxx1100xxx1xxxx", InstName.Vfms, InstEmit32.Vfms_V, OpCode32SimdReg.Create);
|
||||||
SetA32("<<<<11101x01xxxxxxxx101xx1x0xxxx", InstName.Vfnma, InstEmit32.Vfnma_S, OpCode32SimdRegS.Create);
|
|
||||||
SetA32("<<<<11101x01xxxxxxxx101xx0x0xxxx", InstName.Vfnms, InstEmit32.Vfnms_S, OpCode32SimdRegS.Create);
|
|
||||||
SetA32("1111001x0x<<xxxxxxxx0000xxx0xxxx", InstName.Vhadd, InstEmit32.Vhadd, OpCode32SimdReg.Create);
|
SetA32("1111001x0x<<xxxxxxxx0000xxx0xxxx", InstName.Vhadd, InstEmit32.Vhadd, OpCode32SimdReg.Create);
|
||||||
SetA32("111101001x10xxxxxxxxxx00xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, OpCode32SimdMemSingle.Create);
|
SetA32("111101001x10xxxxxxxxxx00xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, OpCode32SimdMemSingle.Create);
|
||||||
SetA32("111101000x10xxxxxxxx0111xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, OpCode32SimdMemPair.Create); // Regs = 1.
|
SetA32("111101000x10xxxxxxxx0111xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, OpCode32SimdMemPair.Create); // Regs = 1.
|
||||||
@@ -860,52 +900,31 @@ namespace ARMeilleure.Decoders
|
|||||||
SetA32("111101000x10xxxxxxxx010xxxxxxxxx", InstName.Vld3, InstEmit32.Vld3, OpCode32SimdMemPair.Create); // Inc = 1/2 (itype).
|
SetA32("111101000x10xxxxxxxx010xxxxxxxxx", InstName.Vld3, InstEmit32.Vld3, OpCode32SimdMemPair.Create); // Inc = 1/2 (itype).
|
||||||
SetA32("111101001x10xxxxxxxxxx11xxxxxxxx", InstName.Vld4, InstEmit32.Vld4, OpCode32SimdMemSingle.Create);
|
SetA32("111101001x10xxxxxxxxxx11xxxxxxxx", InstName.Vld4, InstEmit32.Vld4, OpCode32SimdMemSingle.Create);
|
||||||
SetA32("111101000x10xxxxxxxx000xxxxxxxxx", InstName.Vld4, InstEmit32.Vld4, OpCode32SimdMemPair.Create); // Inc = 1/2 (itype).
|
SetA32("111101000x10xxxxxxxx000xxxxxxxxx", InstName.Vld4, InstEmit32.Vld4, OpCode32SimdMemPair.Create); // Inc = 1/2 (itype).
|
||||||
SetA32("<<<<11001x01xxxxxxxx1011xxxxxxx0", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create);
|
|
||||||
SetA32("<<<<11001x11xxxxxxxx1011xxxxxxx0", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create);
|
|
||||||
SetA32("<<<<11010x11xxxxxxxx1011xxxxxxx0", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create);
|
|
||||||
SetA32("<<<<11001x01xxxxxxxx1010xxxxxxxx", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create);
|
|
||||||
SetA32("<<<<11001x11xxxxxxxx1010xxxxxxxx", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create);
|
|
||||||
SetA32("<<<<11010x11xxxxxxxx1010xxxxxxxx", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create);
|
|
||||||
SetA32("<<<<1101xx01xxxxxxxx101xxxxxxxxx", InstName.Vldr, InstEmit32.Vldr, OpCode32SimdMemImm.Create);
|
|
||||||
SetA32("1111001x0x<<xxxxxxxx0110xxx0xxxx", InstName.Vmax, InstEmit32.Vmax_I, OpCode32SimdReg.Create);
|
SetA32("1111001x0x<<xxxxxxxx0110xxx0xxxx", InstName.Vmax, InstEmit32.Vmax_I, OpCode32SimdReg.Create);
|
||||||
SetA32("111100100x00xxxxxxxx1111xxx0xxxx", InstName.Vmax, InstEmit32.Vmax_V, OpCode32SimdReg.Create);
|
SetA32("111100100x00xxxxxxxx1111xxx0xxxx", InstName.Vmax, InstEmit32.Vmax_V, OpCode32SimdReg.Create);
|
||||||
SetA32("1111001x0x<<xxxxxxxx0110xxx1xxxx", InstName.Vmin, InstEmit32.Vmin_I, OpCode32SimdReg.Create);
|
SetA32("1111001x0x<<xxxxxxxx0110xxx1xxxx", InstName.Vmin, InstEmit32.Vmin_I, OpCode32SimdReg.Create);
|
||||||
SetA32("111100100x10xxxxxxxx1111xxx0xxxx", InstName.Vmin, InstEmit32.Vmin_V, OpCode32SimdReg.Create);
|
SetA32("111100100x10xxxxxxxx1111xxx0xxxx", InstName.Vmin, InstEmit32.Vmin_V, OpCode32SimdReg.Create);
|
||||||
SetA32("111111101x00xxxxxxxx10>>x0x0xxxx", InstName.Vmaxnm, InstEmit32.Vmaxnm_S, OpCode32SimdRegS.Create);
|
|
||||||
SetA32("111100110x0xxxxxxxxx1111xxx1xxxx", InstName.Vmaxnm, InstEmit32.Vmaxnm_V, OpCode32SimdReg.Create);
|
SetA32("111100110x0xxxxxxxxx1111xxx1xxxx", InstName.Vmaxnm, InstEmit32.Vmaxnm_V, OpCode32SimdReg.Create);
|
||||||
SetA32("111111101x00xxxxxxxx10>>x1x0xxxx", InstName.Vminnm, InstEmit32.Vminnm_S, OpCode32SimdRegS.Create);
|
|
||||||
SetA32("111100110x1xxxxxxxxx1111xxx1xxxx", InstName.Vminnm, InstEmit32.Vminnm_V, OpCode32SimdReg.Create);
|
SetA32("111100110x1xxxxxxxxx1111xxx1xxxx", InstName.Vminnm, InstEmit32.Vminnm_V, OpCode32SimdReg.Create);
|
||||||
SetA32("1111001x1x<<xxxxxxxx000xx1x0xxxx", InstName.Vmla, InstEmit32.Vmla_1, OpCode32SimdRegElem.Create);
|
SetA32("1111001x1x<<xxxxxxxx000xx1x0xxxx", InstName.Vmla, InstEmit32.Vmla_1, OpCode32SimdRegElem.Create);
|
||||||
SetA32("111100100xxxxxxxxxxx1001xxx0xxxx", InstName.Vmla, InstEmit32.Vmla_I, OpCode32SimdReg.Create);
|
SetA32("111100100xxxxxxxxxxx1001xxx0xxxx", InstName.Vmla, InstEmit32.Vmla_I, OpCode32SimdReg.Create);
|
||||||
SetA32("<<<<11100x00xxxxxxxx101xx0x0xxxx", InstName.Vmla, InstEmit32.Vmla_S, OpCode32SimdRegS.Create);
|
|
||||||
SetA32("111100100x00xxxxxxxx1101xxx1xxxx", InstName.Vmla, InstEmit32.Vmla_V, OpCode32SimdReg.Create);
|
SetA32("111100100x00xxxxxxxx1101xxx1xxxx", InstName.Vmla, InstEmit32.Vmla_V, OpCode32SimdReg.Create);
|
||||||
SetA32("1111001x1x<<xxxxxxx01000x0x0xxxx", InstName.Vmlal, InstEmit32.Vmlal_I, OpCode32SimdRegLong.Create);
|
SetA32("1111001x1x<<xxxxxxx01000x0x0xxxx", InstName.Vmlal, InstEmit32.Vmlal_I, OpCode32SimdRegLong.Create);
|
||||||
SetA32("1111001x1x<<xxxxxxxx010xx1x0xxxx", InstName.Vmls, InstEmit32.Vmls_1, OpCode32SimdRegElem.Create);
|
SetA32("1111001x1x<<xxxxxxxx010xx1x0xxxx", InstName.Vmls, InstEmit32.Vmls_1, OpCode32SimdRegElem.Create);
|
||||||
SetA32("<<<<11100x00xxxxxxxx101xx1x0xxxx", InstName.Vmls, InstEmit32.Vmls_S, OpCode32SimdRegS.Create);
|
|
||||||
SetA32("111100100x10xxxxxxxx1101xxx1xxxx", InstName.Vmls, InstEmit32.Vmls_V, OpCode32SimdReg.Create);
|
SetA32("111100100x10xxxxxxxx1101xxx1xxxx", InstName.Vmls, InstEmit32.Vmls_V, OpCode32SimdReg.Create);
|
||||||
SetA32("111100110xxxxxxxxxxx1001xxx0xxxx", InstName.Vmls, InstEmit32.Vmls_I, OpCode32SimdReg.Create);
|
SetA32("111100110xxxxxxxxxxx1001xxx0xxxx", InstName.Vmls, InstEmit32.Vmls_I, OpCode32SimdReg.Create);
|
||||||
SetA32("1111001x1x<<xxxxxxx01010x0x0xxxx", InstName.Vmlsl, InstEmit32.Vmlsl_I, OpCode32SimdRegLong.Create);
|
SetA32("1111001x1x<<xxxxxxx01010x0x0xxxx", InstName.Vmlsl, InstEmit32.Vmlsl_I, OpCode32SimdRegLong.Create);
|
||||||
SetA32("<<<<11100xx0xxxxxxxx1011xxx10000", InstName.Vmov, InstEmit32.Vmov_G1, OpCode32SimdMovGpElem.Create); // From gen purpose.
|
|
||||||
SetA32("<<<<1110xxx1xxxxxxxx1011xxx10000", InstName.Vmov, InstEmit32.Vmov_G1, OpCode32SimdMovGpElem.Create); // To gen purpose.
|
|
||||||
SetA32("<<<<1100010xxxxxxxxx101000x1xxxx", InstName.Vmov, InstEmit32.Vmov_G2, OpCode32SimdMovGpDouble.Create); // To/from gen purpose x2 and single precision x2.
|
|
||||||
SetA32("<<<<1100010xxxxxxxxx101100x1xxxx", InstName.Vmov, InstEmit32.Vmov_GD, OpCode32SimdMovGpDouble.Create); // To/from gen purpose x2 and double precision.
|
|
||||||
SetA32("<<<<1110000xxxxxxxxx1010x0010000", InstName.Vmov, InstEmit32.Vmov_GS, OpCode32SimdMovGp.Create); // To/from gen purpose and single precision.
|
|
||||||
SetA32("1111001x1x000xxxxxxx0xx00x01xxxx", InstName.Vmov, InstEmit32.Vmov_I, OpCode32SimdImm.Create); // D/Q vector I32.
|
SetA32("1111001x1x000xxxxxxx0xx00x01xxxx", InstName.Vmov, InstEmit32.Vmov_I, OpCode32SimdImm.Create); // D/Q vector I32.
|
||||||
SetA32("<<<<11101x11xxxxxxxx101x0000xxxx", InstName.Vmov, InstEmit32.Vmov_I, OpCode32SimdImm44.Create); // Scalar f16/32/64 based on size 01 10 11.
|
|
||||||
SetA32("1111001x1x000xxxxxxx10x00x01xxxx", InstName.Vmov, InstEmit32.Vmov_I, OpCode32SimdImm.Create); // D/Q I16.
|
SetA32("1111001x1x000xxxxxxx10x00x01xxxx", InstName.Vmov, InstEmit32.Vmov_I, OpCode32SimdImm.Create); // D/Q I16.
|
||||||
SetA32("1111001x1x000xxxxxxx11xx0x01xxxx", InstName.Vmov, InstEmit32.Vmov_I, OpCode32SimdImm.Create); // D/Q (dt - from cmode).
|
SetA32("1111001x1x000xxxxxxx11xx0x01xxxx", InstName.Vmov, InstEmit32.Vmov_I, OpCode32SimdImm.Create); // D/Q (dt - from cmode).
|
||||||
SetA32("1111001x1x000xxxxxxx11100x11xxxx", InstName.Vmov, InstEmit32.Vmov_I, OpCode32SimdImm.Create); // D/Q I64.
|
SetA32("1111001x1x000xxxxxxx11100x11xxxx", InstName.Vmov, InstEmit32.Vmov_I, OpCode32SimdImm.Create); // D/Q I64.
|
||||||
SetA32("<<<<11101x110000xxxx101x01x0xxxx", InstName.Vmov, InstEmit32.Vmov_S, OpCode32SimdS.Create);
|
|
||||||
SetA32("1111001x1x001000xxx0101000x1xxxx", InstName.Vmovl, InstEmit32.Vmovl, OpCode32SimdLong.Create);
|
SetA32("1111001x1x001000xxx0101000x1xxxx", InstName.Vmovl, InstEmit32.Vmovl, OpCode32SimdLong.Create);
|
||||||
SetA32("1111001x1x010000xxx0101000x1xxxx", InstName.Vmovl, InstEmit32.Vmovl, OpCode32SimdLong.Create);
|
SetA32("1111001x1x010000xxx0101000x1xxxx", InstName.Vmovl, InstEmit32.Vmovl, OpCode32SimdLong.Create);
|
||||||
SetA32("1111001x1x100000xxx0101000x1xxxx", InstName.Vmovl, InstEmit32.Vmovl, OpCode32SimdLong.Create);
|
SetA32("1111001x1x100000xxx0101000x1xxxx", InstName.Vmovl, InstEmit32.Vmovl, OpCode32SimdLong.Create);
|
||||||
SetA32("111100111x11<<10xxxx001000x0xxx0", InstName.Vmovn, InstEmit32.Vmovn, OpCode32SimdMovn.Create);
|
SetA32("111100111x11<<10xxxx001000x0xxx0", InstName.Vmovn, InstEmit32.Vmovn, OpCode32SimdMovn.Create);
|
||||||
SetA32("<<<<11101111xxxxxxxx101000010000", InstName.Vmrs, InstEmit32.Vmrs, OpCode32SimdSpecial.Create);
|
|
||||||
SetA32("<<<<11101110xxxxxxxx101000010000", InstName.Vmsr, InstEmit32.Vmsr, OpCode32SimdSpecial.Create);
|
|
||||||
SetA32("1111001x1x<<xxxxxxxx100xx1x0xxxx", InstName.Vmul, InstEmit32.Vmul_1, OpCode32SimdRegElem.Create);
|
SetA32("1111001x1x<<xxxxxxxx100xx1x0xxxx", InstName.Vmul, InstEmit32.Vmul_1, OpCode32SimdRegElem.Create);
|
||||||
SetA32("111100100x<<xxxxxxxx1001xxx1xxxx", InstName.Vmul, InstEmit32.Vmul_I, OpCode32SimdReg.Create);
|
SetA32("111100100x<<xxxxxxxx1001xxx1xxxx", InstName.Vmul, InstEmit32.Vmul_I, OpCode32SimdReg.Create);
|
||||||
SetA32("111100110x00xxxxxxxx1001xxx1xxxx", InstName.Vmul, InstEmit32.Vmul_I, OpCode32SimdReg.Create);
|
SetA32("111100110x00xxxxxxxx1001xxx1xxxx", InstName.Vmul, InstEmit32.Vmul_I, OpCode32SimdReg.Create);
|
||||||
SetA32("<<<<11100x10xxxxxxxx101xx0x0xxxx", InstName.Vmul, InstEmit32.Vmul_S, OpCode32SimdRegS.Create);
|
|
||||||
SetA32("111100110x00xxxxxxxx1101xxx1xxxx", InstName.Vmul, InstEmit32.Vmul_V, OpCode32SimdReg.Create);
|
SetA32("111100110x00xxxxxxxx1101xxx1xxxx", InstName.Vmul, InstEmit32.Vmul_V, OpCode32SimdReg.Create);
|
||||||
SetA32("1111001x1x<<xxxxxxx01010x1x0xxxx", InstName.Vmull, InstEmit32.Vmull_1, OpCode32SimdRegElemLong.Create);
|
SetA32("1111001x1x<<xxxxxxx01010x1x0xxxx", InstName.Vmull, InstEmit32.Vmull_1, OpCode32SimdRegElemLong.Create);
|
||||||
SetA32("1111001x1x<<xxxxxxx01100x0x0xxxx", InstName.Vmull, InstEmit32.Vmull_I, OpCode32SimdRegLong.Create);
|
SetA32("1111001x1x<<xxxxxxx01100x0x0xxxx", InstName.Vmull, InstEmit32.Vmull_I, OpCode32SimdRegLong.Create);
|
||||||
@@ -914,12 +933,8 @@ namespace ARMeilleure.Decoders
|
|||||||
SetA32("1111001x1x000xxxxxxx0xx00x11xxxx", InstName.Vmvn, InstEmit32.Vmvn_II, OpCode32SimdImm.Create); // D/Q vector I32.
|
SetA32("1111001x1x000xxxxxxx0xx00x11xxxx", InstName.Vmvn, InstEmit32.Vmvn_II, OpCode32SimdImm.Create); // D/Q vector I32.
|
||||||
SetA32("1111001x1x000xxxxxxx10x00x11xxxx", InstName.Vmvn, InstEmit32.Vmvn_II, OpCode32SimdImm.Create);
|
SetA32("1111001x1x000xxxxxxx10x00x11xxxx", InstName.Vmvn, InstEmit32.Vmvn_II, OpCode32SimdImm.Create);
|
||||||
SetA32("1111001x1x000xxxxxxx110x0x11xxxx", InstName.Vmvn, InstEmit32.Vmvn_II, OpCode32SimdImm.Create);
|
SetA32("1111001x1x000xxxxxxx110x0x11xxxx", InstName.Vmvn, InstEmit32.Vmvn_II, OpCode32SimdImm.Create);
|
||||||
SetA32("<<<<11101x110001xxxx101x01x0xxxx", InstName.Vneg, InstEmit32.Vneg_S, OpCode32SimdS.Create);
|
|
||||||
SetA32("111100111x11<<01xxxx00111xx0xxxx", InstName.Vneg, InstEmit32.Vneg_V, OpCode32SimdCmpZ.Create);
|
SetA32("111100111x11<<01xxxx00111xx0xxxx", InstName.Vneg, InstEmit32.Vneg_V, OpCode32SimdCmpZ.Create);
|
||||||
SetA32("111100111x111001xxxx01111xx0xxxx", InstName.Vneg, InstEmit32.Vneg_V, OpCode32SimdCmpZ.Create);
|
SetA32("111100111x111001xxxx01111xx0xxxx", InstName.Vneg, InstEmit32.Vneg_V, OpCode32SimdCmpZ.Create);
|
||||||
SetA32("<<<<11100x01xxxxxxxx101xx1x0xxxx", InstName.Vnmla, InstEmit32.Vnmla_S, OpCode32SimdRegS.Create);
|
|
||||||
SetA32("<<<<11100x01xxxxxxxx101xx0x0xxxx", InstName.Vnmls, InstEmit32.Vnmls_S, OpCode32SimdRegS.Create);
|
|
||||||
SetA32("<<<<11100x10xxxxxxxx101xx1x0xxxx", InstName.Vnmul, InstEmit32.Vnmul_S, OpCode32SimdRegS.Create);
|
|
||||||
SetA32("111100100x11xxxxxxxx0001xxx1xxxx", InstName.Vorn, InstEmit32.Vorn_I, OpCode32SimdBinary.Create);
|
SetA32("111100100x11xxxxxxxx0001xxx1xxxx", InstName.Vorn, InstEmit32.Vorn_I, OpCode32SimdBinary.Create);
|
||||||
SetA32("111100100x10xxxxxxxx0001xxx1xxxx", InstName.Vorr, InstEmit32.Vorr_I, OpCode32SimdBinary.Create);
|
SetA32("111100100x10xxxxxxxx0001xxx1xxxx", InstName.Vorr, InstEmit32.Vorr_I, OpCode32SimdBinary.Create);
|
||||||
SetA32("1111001x1x000xxxxxxx<<x10x01xxxx", InstName.Vorr, InstEmit32.Vorr_II, OpCode32SimdImm.Create);
|
SetA32("1111001x1x000xxxxxxx<<x10x01xxxx", InstName.Vorr, InstEmit32.Vorr_II, OpCode32SimdImm.Create);
|
||||||
@@ -944,21 +959,20 @@ namespace ARMeilleure.Decoders
|
|||||||
SetA32("111100100x00xxxxxxxx1111xxx1xxxx", InstName.Vrecps, InstEmit32.Vrecps, OpCode32SimdReg.Create);
|
SetA32("111100100x00xxxxxxxx1111xxx1xxxx", InstName.Vrecps, InstEmit32.Vrecps, OpCode32SimdReg.Create);
|
||||||
SetA32("111100111x11xx00xxxx000<<xx0xxxx", InstName.Vrev, InstEmit32.Vrev, OpCode32SimdRev.Create);
|
SetA32("111100111x11xx00xxxx000<<xx0xxxx", InstName.Vrev, InstEmit32.Vrev, OpCode32SimdRev.Create);
|
||||||
SetA32("1111001x0x<<xxxxxxxx0001xxx0xxxx", InstName.Vrhadd, InstEmit32.Vrhadd, OpCode32SimdReg.Create);
|
SetA32("1111001x0x<<xxxxxxxx0001xxx0xxxx", InstName.Vrhadd, InstEmit32.Vrhadd, OpCode32SimdReg.Create);
|
||||||
SetA32("111111101x1110xxxxxx101x01x0xxxx", InstName.Vrint, InstEmit32.Vrint_RM, OpCode32SimdS.Create);
|
SetA32("111100111x111010xxxx01010xx0xxxx", InstName.Vrinta, InstEmit32.Vrinta_V, OpCode32SimdCmpZ.Create);
|
||||||
SetA32("<<<<11101x110110xxxx101x11x0xxxx", InstName.Vrint, InstEmit32.Vrint_Z, OpCode32SimdS.Create);
|
SetA32("111100111x111010xxxx01101xx0xxxx", InstName.Vrintm, InstEmit32.Vrintm_V, OpCode32SimdCmpZ.Create);
|
||||||
SetA32("<<<<11101x110111xxxx101x01x0xxxx", InstName.Vrintx, InstEmit32.Vrintx_S, OpCode32SimdS.Create);
|
SetA32("111100111x111010xxxx01000xx0xxxx", InstName.Vrintn, InstEmit32.Vrintn_V, OpCode32SimdCmpZ.Create);
|
||||||
|
SetA32("111100111x111010xxxx01111xx0xxxx", InstName.Vrintp, InstEmit32.Vrintp_V, OpCode32SimdCmpZ.Create);
|
||||||
SetA32("1111001x1x>>>xxxxxxx0010>xx1xxxx", InstName.Vrshr, InstEmit32.Vrshr, OpCode32SimdShImm.Create);
|
SetA32("1111001x1x>>>xxxxxxx0010>xx1xxxx", InstName.Vrshr, InstEmit32.Vrshr, OpCode32SimdShImm.Create);
|
||||||
SetA32("111100101x>>>xxxxxxx100001x1xxx0", InstName.Vrshrn, InstEmit32.Vrshrn, OpCode32SimdShImmNarrow.Create);
|
SetA32("111100101x>>>xxxxxxx100001x1xxx0", InstName.Vrshrn, InstEmit32.Vrshrn, OpCode32SimdShImmNarrow.Create);
|
||||||
SetA32("111100111x111011xxxx010x1xx0xxxx", InstName.Vrsqrte, InstEmit32.Vrsqrte, OpCode32SimdSqrte.Create);
|
SetA32("111100111x111011xxxx010x1xx0xxxx", InstName.Vrsqrte, InstEmit32.Vrsqrte, OpCode32SimdSqrte.Create);
|
||||||
SetA32("111100100x10xxxxxxxx1111xxx1xxxx", InstName.Vrsqrts, InstEmit32.Vrsqrts, OpCode32SimdReg.Create);
|
SetA32("111100100x10xxxxxxxx1111xxx1xxxx", InstName.Vrsqrts, InstEmit32.Vrsqrts, OpCode32SimdReg.Create);
|
||||||
SetA32("1111001x1x>>>xxxxxxx0011>xx1xxxx", InstName.Vrsra, InstEmit32.Vrsra, OpCode32SimdShImm.Create);
|
SetA32("1111001x1x>>>xxxxxxx0011>xx1xxxx", InstName.Vrsra, InstEmit32.Vrsra, OpCode32SimdShImm.Create);
|
||||||
SetA32("111111100xxxxxxxxxxx101xx0x0xxxx", InstName.Vsel, InstEmit32.Vsel, OpCode32SimdSel.Create);
|
|
||||||
SetA32("111100101x>>>xxxxxxx0101>xx1xxxx", InstName.Vshl, InstEmit32.Vshl, OpCode32SimdShImm.Create);
|
SetA32("111100101x>>>xxxxxxx0101>xx1xxxx", InstName.Vshl, InstEmit32.Vshl, OpCode32SimdShImm.Create);
|
||||||
SetA32("1111001x0xxxxxxxxxxx0100xxx0xxxx", InstName.Vshl, InstEmit32.Vshl_I, OpCode32SimdReg.Create);
|
SetA32("1111001x0xxxxxxxxxxx0100xxx0xxxx", InstName.Vshl, InstEmit32.Vshl_I, OpCode32SimdReg.Create);
|
||||||
SetA32("1111001x1x>>>xxxxxxx101000x1xxxx", InstName.Vshll, InstEmit32.Vshll, OpCode32SimdShImmLong.Create); // A1 encoding.
|
SetA32("1111001x1x>>>xxxxxxx101000x1xxxx", InstName.Vshll, InstEmit32.Vshll, OpCode32SimdShImmLong.Create); // A1 encoding.
|
||||||
SetA32("1111001x1x>>>xxxxxxx0000>xx1xxxx", InstName.Vshr, InstEmit32.Vshr, OpCode32SimdShImm.Create);
|
SetA32("1111001x1x>>>xxxxxxx0000>xx1xxxx", InstName.Vshr, InstEmit32.Vshr, OpCode32SimdShImm.Create);
|
||||||
SetA32("111100101x>>>xxxxxxx100000x1xxx0", InstName.Vshrn, InstEmit32.Vshrn, OpCode32SimdShImmNarrow.Create);
|
SetA32("111100101x>>>xxxxxxx100000x1xxx0", InstName.Vshrn, InstEmit32.Vshrn, OpCode32SimdShImmNarrow.Create);
|
||||||
SetA32("<<<<11101x110001xxxx101x11x0xxxx", InstName.Vsqrt, InstEmit32.Vsqrt_S, OpCode32SimdS.Create);
|
|
||||||
SetA32("1111001x1x>>>xxxxxxx0001>xx1xxxx", InstName.Vsra, InstEmit32.Vsra, OpCode32SimdShImm.Create);
|
SetA32("1111001x1x>>>xxxxxxx0001>xx1xxxx", InstName.Vsra, InstEmit32.Vsra, OpCode32SimdShImm.Create);
|
||||||
SetA32("111101001x00xxxxxxxx<<00xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemSingle.Create);
|
SetA32("111101001x00xxxxxxxx<<00xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemSingle.Create);
|
||||||
SetA32("111101000x00xxxxxxxx0111xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemPair.Create); // Regs = 1.
|
SetA32("111101000x00xxxxxxxx0111xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemPair.Create); // Regs = 1.
|
||||||
@@ -972,15 +986,7 @@ namespace ARMeilleure.Decoders
|
|||||||
SetA32("111101000x00xxxxxxxx010xxxxxxxxx", InstName.Vst3, InstEmit32.Vst3, OpCode32SimdMemPair.Create); // Inc = 1/2 (itype).
|
SetA32("111101000x00xxxxxxxx010xxxxxxxxx", InstName.Vst3, InstEmit32.Vst3, OpCode32SimdMemPair.Create); // Inc = 1/2 (itype).
|
||||||
SetA32("111101001x00xxxxxxxx<<11xxxxxxxx", InstName.Vst4, InstEmit32.Vst4, OpCode32SimdMemSingle.Create);
|
SetA32("111101001x00xxxxxxxx<<11xxxxxxxx", InstName.Vst4, InstEmit32.Vst4, OpCode32SimdMemSingle.Create);
|
||||||
SetA32("111101000x00xxxxxxxx000xxxxxxxxx", InstName.Vst4, InstEmit32.Vst4, OpCode32SimdMemPair.Create); // Inc = 1/2 (itype).
|
SetA32("111101000x00xxxxxxxx000xxxxxxxxx", InstName.Vst4, InstEmit32.Vst4, OpCode32SimdMemPair.Create); // Inc = 1/2 (itype).
|
||||||
SetA32("<<<<11001x00xxxxxxxx1011xxxxxxx0", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create);
|
|
||||||
SetA32("<<<<11001x10xxxxxxxx1011xxxxxxx0", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create);
|
|
||||||
SetA32("<<<<11010x10xxxxxxxx1011xxxxxxx0", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create);
|
|
||||||
SetA32("<<<<11001x00xxxxxxxx1010xxxxxxxx", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create);
|
|
||||||
SetA32("<<<<11001x10xxxxxxxx1010xxxxxxxx", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create);
|
|
||||||
SetA32("<<<<11010x10xxxxxxxx1010xxxxxxxx", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create);
|
|
||||||
SetA32("<<<<1101xx00xxxxxxxx101xxxxxxxxx", InstName.Vstr, InstEmit32.Vstr, OpCode32SimdMemImm.Create);
|
|
||||||
SetA32("111100110xxxxxxxxxxx1000xxx0xxxx", InstName.Vsub, InstEmit32.Vsub_I, OpCode32SimdReg.Create);
|
SetA32("111100110xxxxxxxxxxx1000xxx0xxxx", InstName.Vsub, InstEmit32.Vsub_I, OpCode32SimdReg.Create);
|
||||||
SetA32("<<<<11100x11xxxxxxxx101xx1x0xxxx", InstName.Vsub, InstEmit32.Vsub_S, OpCode32SimdRegS.Create);
|
|
||||||
SetA32("111100100x10xxxxxxxx1101xxx0xxxx", InstName.Vsub, InstEmit32.Vsub_V, OpCode32SimdReg.Create);
|
SetA32("111100100x10xxxxxxxx1101xxx0xxxx", InstName.Vsub, InstEmit32.Vsub_V, OpCode32SimdReg.Create);
|
||||||
SetA32("1111001x1x<<xxxxxxx00010x0x0xxxx", InstName.Vsubl, InstEmit32.Vsubl_I, OpCode32SimdRegLong.Create);
|
SetA32("1111001x1x<<xxxxxxx00010x0x0xxxx", InstName.Vsubl, InstEmit32.Vsubl_I, OpCode32SimdRegLong.Create);
|
||||||
SetA32("1111001x1x<<xxxxxxx00011x0x0xxxx", InstName.Vsubw, InstEmit32.Vsubw_I, OpCode32SimdRegWide.Create);
|
SetA32("1111001x1x<<xxxxxxx00011x0x0xxxx", InstName.Vsubw, InstEmit32.Vsubw_I, OpCode32SimdRegWide.Create);
|
||||||
@@ -1021,7 +1027,7 @@ namespace ARMeilleure.Decoders
|
|||||||
SetT16("01000101xxxxxxxx", InstName.Cmp, InstEmit32.Cmp, OpCodeT16AluRegHigh.Create);
|
SetT16("01000101xxxxxxxx", InstName.Cmp, InstEmit32.Cmp, OpCodeT16AluRegHigh.Create);
|
||||||
SetT16("01000110xxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16AluRegHigh.Create);
|
SetT16("01000110xxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16AluRegHigh.Create);
|
||||||
SetT16("010001110xxxx000", InstName.Bx, InstEmit32.Bx, OpCodeT16BReg.Create);
|
SetT16("010001110xxxx000", InstName.Bx, InstEmit32.Bx, OpCodeT16BReg.Create);
|
||||||
SetT16("010001111xxxx000", InstName.Blx, InstEmit32.Blx, OpCodeT16BReg.Create);
|
SetT16("010001111xxxx000", InstName.Blx, InstEmit32.Blxr, OpCodeT16BReg.Create);
|
||||||
SetT16("01001xxxxxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT16MemLit.Create);
|
SetT16("01001xxxxxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT16MemLit.Create);
|
||||||
SetT16("0101000xxxxxxxxx", InstName.Str, InstEmit32.Str, OpCodeT16MemReg.Create);
|
SetT16("0101000xxxxxxxxx", InstName.Str, InstEmit32.Str, OpCodeT16MemReg.Create);
|
||||||
SetT16("0101001xxxxxxxxx", InstName.Strh, InstEmit32.Strh, OpCodeT16MemReg.Create);
|
SetT16("0101001xxxxxxxxx", InstName.Strh, InstEmit32.Strh, OpCodeT16MemReg.Create);
|
||||||
@@ -1069,49 +1075,71 @@ namespace ARMeilleure.Decoders
|
|||||||
SetT32("11110x01010xxxxx0xxxxxxxxxxxxxxx", InstName.Adc, InstEmit32.Adc, OpCodeT32AluImm.Create);
|
SetT32("11110x01010xxxxx0xxxxxxxxxxxxxxx", InstName.Adc, InstEmit32.Adc, OpCodeT32AluImm.Create);
|
||||||
SetT32("11101011000<xxxx0xxx<<<<xxxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT32AluRsImm.Create);
|
SetT32("11101011000<xxxx0xxx<<<<xxxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT32AluRsImm.Create);
|
||||||
SetT32("11110x01000<xxxx0xxx<<<<xxxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT32AluImm.Create);
|
SetT32("11110x01000<xxxx0xxx<<<<xxxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT32AluImm.Create);
|
||||||
|
SetT32("11110x100000xxxx0xxxxxxxxxxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT32AluImm12.Create);
|
||||||
SetT32("11101010000<xxxx0xxx<<<<xxxxxxxx", InstName.And, InstEmit32.And, OpCodeT32AluRsImm.Create);
|
SetT32("11101010000<xxxx0xxx<<<<xxxxxxxx", InstName.And, InstEmit32.And, OpCodeT32AluRsImm.Create);
|
||||||
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);
|
||||||
SetT32("11110xxxxxxxxxxx11x0xxxxxxxxxxx0", InstName.Blx, InstEmit32.Blx, OpCodeT32BImm24.Create);
|
SetT32("11110xxxxxxxxxxx11x0xxxxxxxxxxx0", InstName.Blx, InstEmit32.Blx, OpCodeT32BImm24.Create);
|
||||||
|
SetT32("111110101011xxxx1111xxxx1000xxxx", InstName.Clz, InstEmit32.Clz, OpCodeT32AluReg.Create);
|
||||||
SetT32("111010110001xxxx0xxx1111xxxxxxxx", InstName.Cmn, InstEmit32.Cmn, OpCodeT32AluRsImm.Create);
|
SetT32("111010110001xxxx0xxx1111xxxxxxxx", InstName.Cmn, InstEmit32.Cmn, OpCodeT32AluRsImm.Create);
|
||||||
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("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("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("111110000001xxxxxxxx1100xxxxxxxx", 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("111110001001xxxxxxxxxxxxxxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT32MemImm12.Create);
|
||||||
SetT32("1110100>x1>1<<<<xxxxxxxxxxxxxxxx", InstName.Ldrd, InstEmit32.Ldrd, OpCodeT32MemImm8D.Create);
|
SetT32("111110000001xxxx<<<<000000xxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT32MemRsImm.Create);
|
||||||
SetT32("111110000011xxxx<<<<10x1xxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT32MemImm8.Create);
|
SetT32("11101000x111<<<<xxxxxxxxxxxxxxxx", InstName.Ldrd, InstEmit32.Ldrd, OpCodeT32MemImm8D.Create);
|
||||||
SetT32("111110000011xxxx<<<<1100xxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT32MemImm8.Create);
|
SetT32("11101001x1x1<<<<xxxxxxxxxxxxxxxx", InstName.Ldrd, InstEmit32.Ldrd, OpCodeT32MemImm8D.Create);
|
||||||
SetT32("111110000011xxxx<<<<11x1xxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT32MemImm8.Create);
|
SetT32("111110000011xxxxxxxx10x1xxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT32MemImm8.Create);
|
||||||
|
SetT32("111110000011xxxxxxxx1100xxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT32MemImm8.Create);
|
||||||
|
SetT32("111110000011xxxxxxxx11x1xxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT32MemImm8.Create);
|
||||||
SetT32("111110001011xxxxxxxxxxxxxxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT32MemImm12.Create);
|
SetT32("111110001011xxxxxxxxxxxxxxxxxxxx", 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("111110010001xxxx<<<<1100xxxxxxxx", InstName.Ldrsb, InstEmit32.Ldrsb, OpCodeT32MemImm8.Create);
|
SetT32("111110010001xxxxxxxx10x1xxxxxxxx", InstName.Ldrsb, InstEmit32.Ldrsb, OpCodeT32MemImm8.Create);
|
||||||
SetT32("111110010001xxxx<<<<11x1xxxxxxxx", InstName.Ldrsb, InstEmit32.Ldrsb, OpCodeT32MemImm8.Create);
|
SetT32("111110010001xxxxxxxx1100xxxxxxxx", InstName.Ldrsb, InstEmit32.Ldrsb, OpCodeT32MemImm8.Create);
|
||||||
|
SetT32("111110010001xxxxxxxx11x1xxxxxxxx", InstName.Ldrsb, InstEmit32.Ldrsb, OpCodeT32MemImm8.Create);
|
||||||
SetT32("111110011001xxxxxxxxxxxxxxxxxxxx", InstName.Ldrsb, InstEmit32.Ldrsb, OpCodeT32MemImm12.Create);
|
SetT32("111110011001xxxxxxxxxxxxxxxxxxxx", 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("111110010011xxxx<<<<1100xxxxxxxx", InstName.Ldrsh, InstEmit32.Ldrsh, OpCodeT32MemImm8.Create);
|
SetT32("111110010011xxxxxxxx10x1xxxxxxxx", InstName.Ldrsh, InstEmit32.Ldrsh, OpCodeT32MemImm8.Create);
|
||||||
SetT32("111110010011xxxx<<<<11x1xxxxxxxx", InstName.Ldrsh, InstEmit32.Ldrsh, OpCodeT32MemImm8.Create);
|
SetT32("111110010011xxxxxxxx1100xxxxxxxx", InstName.Ldrsh, InstEmit32.Ldrsh, OpCodeT32MemImm8.Create);
|
||||||
|
SetT32("111110010011xxxxxxxx11x1xxxxxxxx", InstName.Ldrsh, InstEmit32.Ldrsh, OpCodeT32MemImm8.Create);
|
||||||
SetT32("111110011011xxxxxxxxxxxxxxxxxxxx", InstName.Ldrsh, InstEmit32.Ldrsh, OpCodeT32MemImm12.Create);
|
SetT32("111110011011xxxxxxxxxxxxxxxxxxxx", 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("11110x00010x11110xxxxxxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT32AluImm.Create);
|
SetT32("11110x00010x11110xxxxxxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT32AluImm.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("11101010011x<<<<0xxxxxxxxxxxxxxx", InstName.Orn, InstEmit32.Orn, OpCodeT32AluRsImm.Create);
|
SetT32("11101010011x<<<<0xxxxxxxxxxxxxxx", InstName.Orn, InstEmit32.Orn, OpCodeT32AluRsImm.Create);
|
||||||
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);
|
||||||
@@ -1120,7 +1148,24 @@ namespace ARMeilleure.Decoders
|
|||||||
SetT32("11110x01110xxxxx0xxxxxxxxxxxxxxx", InstName.Rsb, InstEmit32.Rsb, OpCodeT32AluImm.Create);
|
SetT32("11110x01110xxxxx0xxxxxxxxxxxxxxx", InstName.Rsb, InstEmit32.Rsb, OpCodeT32AluImm.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("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("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("111110000100xxxxxxxx1<<>xxxxxxxx", InstName.Str, InstEmit32.Str, OpCodeT32MemImm8.Create);
|
||||||
@@ -1128,15 +1173,31 @@ namespace ARMeilleure.Decoders
|
|||||||
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("111110000000xxxxxxxx1<<>xxxxxxxx", InstName.Strb, InstEmit32.Strb, OpCodeT32MemImm8.Create);
|
||||||
SetT32("111110001000xxxxxxxxxxxxxxxxxxxx", InstName.Strb, InstEmit32.Strb, OpCodeT32MemImm12.Create);
|
SetT32("111110001000xxxxxxxxxxxxxxxxxxxx", InstName.Strb, InstEmit32.Strb, OpCodeT32MemImm12.Create);
|
||||||
SetT32("1110100>x1>0<<<<xxxxxxxxxxxxxxxx", InstName.Strd, InstEmit32.Strd, OpCodeT32MemImm8D.Create);
|
SetT32("111110000000<<<<xxxx000000xxxxxx", InstName.Strb, InstEmit32.Strb, OpCodeT32MemRsImm.Create);
|
||||||
|
SetT32("11101000x110<<<<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("111110000010xxxxxxxx1<<>xxxxxxxx", InstName.Strh, InstEmit32.Strh, OpCodeT32MemImm8.Create);
|
||||||
SetT32("111110001010xxxxxxxxxxxxxxxxxxxx", InstName.Strh, InstEmit32.Strh, OpCodeT32MemImm12.Create);
|
SetT32("111110001010xxxxxxxxxxxxxxxxxxxx", 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("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("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("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("111100111100xxxx0xxxxxxxxx0xxxxx", InstName.Ubfx, InstEmit32.Ubfx, OpCodeT32AluBf.Create);
|
||||||
|
SetT32("111110111011xxxx1111xxxx1111xxxx", InstName.Udiv, InstEmit32.Udiv, OpCodeT32AluMla.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("111110100101xxxx1111xxxx10xxxxxx", InstName.Uxtb, InstEmit32.Uxtb, OpCodeT32AluUx.Create);
|
||||||
|
SetT32("111110100011xxxx1111xxxx10xxxxxx", InstName.Uxtb16, InstEmit32.Uxtb16, OpCodeT32AluUx.Create);
|
||||||
|
SetT32("111110100001xxxx1111xxxx10xxxxxx", InstName.Uxth, InstEmit32.Uxth, OpCodeT32AluUx.Create);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
FillFastLookupTable(InstA32FastLookup, AllInstA32, ToFastLookupIndexA);
|
FillFastLookupTable(InstA32FastLookup, AllInstA32, ToFastLookupIndexA);
|
||||||
@@ -1193,6 +1254,18 @@ 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 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.
|
||||||
@@ -389,7 +389,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.
|
||||||
|
|
||||||
@@ -484,7 +484,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
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.
|
||||||
|
|
||||||
|
@@ -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
|
||||||
@@ -107,5 +107,30 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
context.SetIfThenBlockState(op.IfThenBlockConds);
|
context.SetIfThenBlockState(op.IfThenBlockConds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Tbb(ArmEmitterContext context) => EmitTb(context, halfword: false);
|
||||||
|
public static void Tbh(ArmEmitterContext context) => EmitTb(context, halfword: true);
|
||||||
|
|
||||||
|
private static void EmitTb(ArmEmitterContext context, bool halfword)
|
||||||
|
{
|
||||||
|
OpCodeT32Tb op = (OpCodeT32Tb)context.CurrOp;
|
||||||
|
|
||||||
|
Operand halfwords;
|
||||||
|
|
||||||
|
if (halfword)
|
||||||
|
{
|
||||||
|
Operand address = context.Add(GetIntA32(context, op.Rn), context.ShiftLeft(GetIntA32(context, op.Rm), Const(1)));
|
||||||
|
halfwords = InstEmitMemoryHelper.EmitReadInt(context, address, 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Operand address = context.Add(GetIntA32(context, op.Rn), GetIntA32(context, op.Rm));
|
||||||
|
halfwords = InstEmitMemoryHelper.EmitReadIntAligned(context, address, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand targetAddress = context.Add(Const((int)op.GetPc()), context.ShiftLeft(halfwords, Const(1)));
|
||||||
|
|
||||||
|
EmitVirtualJump(context, targetAddress, isReturn: false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -204,15 +204,15 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
context.BranchIfTrue(lblBigEndian, GetFlag(PState.EFlag));
|
context.BranchIfTrue(lblBigEndian, GetFlag(PState.EFlag));
|
||||||
|
|
||||||
Load(op.Rt, 0, WordSizeLog2);
|
Load(op.Rt, 0, WordSizeLog2);
|
||||||
Load(op.Rt | 1, 4, WordSizeLog2);
|
Load(op.Rt2, 4, WordSizeLog2);
|
||||||
|
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
context.MarkLabel(lblBigEndian);
|
context.MarkLabel(lblBigEndian);
|
||||||
|
|
||||||
Load(op.Rt | 1, 0, WordSizeLog2);
|
Load(op.Rt2, 0, WordSizeLog2);
|
||||||
Load(op.Rt, 4, WordSizeLog2);
|
Load(op.Rt, 4, WordSizeLog2);
|
||||||
|
|
||||||
context.MarkLabel(lblEnd);
|
context.MarkLabel(lblEnd);
|
||||||
}
|
}
|
||||||
@@ -237,15 +237,15 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
context.BranchIfTrue(lblBigEndian, GetFlag(PState.EFlag));
|
context.BranchIfTrue(lblBigEndian, GetFlag(PState.EFlag));
|
||||||
|
|
||||||
Store(op.Rt, 0, WordSizeLog2);
|
Store(op.Rt, 0, WordSizeLog2);
|
||||||
Store(op.Rt | 1, 4, WordSizeLog2);
|
Store(op.Rt2, 4, WordSizeLog2);
|
||||||
|
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
context.MarkLabel(lblBigEndian);
|
context.MarkLabel(lblBigEndian);
|
||||||
|
|
||||||
Store(op.Rt | 1, 0, WordSizeLog2);
|
Store(op.Rt2, 0, WordSizeLog2);
|
||||||
Store(op.Rt, 4, WordSizeLog2);
|
Store(op.Rt, 4, WordSizeLog2);
|
||||||
|
|
||||||
context.MarkLabel(lblEnd);
|
context.MarkLabel(lblEnd);
|
||||||
}
|
}
|
||||||
|
@@ -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();
|
||||||
|
@@ -123,6 +123,41 @@ namespace ARMeilleure.Instructions
|
|||||||
context.CurrOp is OpCodeSimdMemSs);
|
context.CurrOp is OpCodeSimdMemSs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Operand EmitReadInt(ArmEmitterContext context, Operand address, int size)
|
||||||
|
{
|
||||||
|
Operand temp = context.AllocateLocal(size == 3 ? OperandType.I64 : OperandType.I32);
|
||||||
|
|
||||||
|
Operand lblSlowPath = Label();
|
||||||
|
Operand lblEnd = Label();
|
||||||
|
|
||||||
|
Operand physAddr = EmitPtPointerLoad(context, address, lblSlowPath, write: false, size);
|
||||||
|
|
||||||
|
Operand value = default;
|
||||||
|
|
||||||
|
switch (size)
|
||||||
|
{
|
||||||
|
case 0: value = context.Load8 (physAddr); break;
|
||||||
|
case 1: value = context.Load16(physAddr); break;
|
||||||
|
case 2: value = context.Load (OperandType.I32, physAddr); break;
|
||||||
|
case 3: value = context.Load (OperandType.I64, physAddr); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Copy(temp, value);
|
||||||
|
|
||||||
|
if (!context.Memory.Type.IsHostMapped())
|
||||||
|
{
|
||||||
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
|
context.MarkLabel(lblSlowPath, BasicBlockFrequency.Cold);
|
||||||
|
|
||||||
|
context.Copy(temp, EmitReadIntFallback(context, address, size));
|
||||||
|
|
||||||
|
context.MarkLabel(lblEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
private static void EmitReadInt(ArmEmitterContext context, Operand address, int rt, int size)
|
private static void EmitReadInt(ArmEmitterContext context, Operand address, int rt, int size)
|
||||||
{
|
{
|
||||||
Operand lblSlowPath = Label();
|
Operand lblSlowPath = Label();
|
||||||
@@ -419,6 +454,11 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitReadIntFallback(ArmEmitterContext context, Operand address, int rt, int size)
|
private static void EmitReadIntFallback(ArmEmitterContext context, Operand address, int rt, int size)
|
||||||
|
{
|
||||||
|
SetInt(context, rt, EmitReadIntFallback(context, address, size));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Operand EmitReadIntFallback(ArmEmitterContext context, Operand address, int size)
|
||||||
{
|
{
|
||||||
MethodInfo info = null;
|
MethodInfo info = null;
|
||||||
|
|
||||||
@@ -430,7 +470,7 @@ namespace ARMeilleure.Instructions
|
|||||||
case 3: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64)); break;
|
case 3: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64)); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetInt(context, rt, context.Call(info, address));
|
return context.Call(info, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitReadVectorFallback(
|
private static void EmitReadVectorFallback(
|
||||||
|
@@ -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)
|
||||||
{
|
{
|
||||||
|
@@ -545,6 +545,8 @@ namespace ARMeilleure.Instructions
|
|||||||
Strexh,
|
Strexh,
|
||||||
Strh,
|
Strh,
|
||||||
Sxtb16,
|
Sxtb16,
|
||||||
|
Tbb,
|
||||||
|
Tbh,
|
||||||
Teq,
|
Teq,
|
||||||
Trap,
|
Trap,
|
||||||
Tst,
|
Tst,
|
||||||
@@ -634,6 +636,10 @@ namespace ARMeilleure.Instructions
|
|||||||
Vrev,
|
Vrev,
|
||||||
Vrhadd,
|
Vrhadd,
|
||||||
Vrint,
|
Vrint,
|
||||||
|
Vrinta,
|
||||||
|
Vrintm,
|
||||||
|
Vrintn,
|
||||||
|
Vrintp,
|
||||||
Vrintx,
|
Vrintx,
|
||||||
Vrshr,
|
Vrshr,
|
||||||
Vrshrn,
|
Vrshrn,
|
||||||
|
@@ -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 = 3677; //! To be incremented manually for each change to the ARMeilleure project.
|
private const uint InternalVersion = 3683; //! 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";
|
||||||
|
10
README.md
10
README.md
@@ -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.
|
||||||
|
|
||||||
|
@@ -55,7 +55,6 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
private uint _processHandle;
|
private uint _processHandle;
|
||||||
private ulong _appletResourceId;
|
private ulong _appletResourceId;
|
||||||
|
|
||||||
private WritableRegion _workBufferRegion;
|
|
||||||
private MemoryHandle _workBufferMemoryPin;
|
private MemoryHandle _workBufferMemoryPin;
|
||||||
|
|
||||||
private Memory<float> _mixBuffer;
|
private Memory<float> _mixBuffer;
|
||||||
@@ -98,7 +97,15 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
_sessionId = 0;
|
_sessionId = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResultCode Initialize(ref AudioRendererConfiguration parameter, uint processHandle, CpuAddress workBuffer, ulong workBufferSize, int sessionId, ulong appletResourceId, IVirtualMemoryManager memoryManager)
|
public ResultCode Initialize(
|
||||||
|
ref AudioRendererConfiguration parameter,
|
||||||
|
uint processHandle,
|
||||||
|
Memory<byte> workBufferMemory,
|
||||||
|
CpuAddress workBuffer,
|
||||||
|
ulong workBufferSize,
|
||||||
|
int sessionId,
|
||||||
|
ulong appletResourceId,
|
||||||
|
IVirtualMemoryManager memoryManager)
|
||||||
{
|
{
|
||||||
if (!BehaviourContext.CheckValidRevision(parameter.Revision))
|
if (!BehaviourContext.CheckValidRevision(parameter.Revision))
|
||||||
{
|
{
|
||||||
@@ -134,11 +141,10 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
|
|
||||||
WorkBufferAllocator workBufferAllocator;
|
WorkBufferAllocator workBufferAllocator;
|
||||||
|
|
||||||
_workBufferRegion = MemoryManager.GetWritableRegion(workBuffer, (int)workBufferSize);
|
workBufferMemory.Span.Fill(0);
|
||||||
_workBufferRegion.Memory.Span.Fill(0);
|
_workBufferMemoryPin = workBufferMemory.Pin();
|
||||||
_workBufferMemoryPin = _workBufferRegion.Memory.Pin();
|
|
||||||
|
|
||||||
workBufferAllocator = new WorkBufferAllocator(_workBufferRegion.Memory);
|
workBufferAllocator = new WorkBufferAllocator(workBufferMemory);
|
||||||
|
|
||||||
PoolMapper poolMapper = new PoolMapper(processHandle, false);
|
PoolMapper poolMapper = new PoolMapper(processHandle, false);
|
||||||
poolMapper.InitializeSystemPool(ref _dspMemoryPoolState, workBuffer, workBufferSize);
|
poolMapper.InitializeSystemPool(ref _dspMemoryPoolState, workBuffer, workBufferSize);
|
||||||
@@ -841,7 +847,6 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
_manager.Unregister(this);
|
_manager.Unregister(this);
|
||||||
_terminationEvent.Dispose();
|
_terminationEvent.Dispose();
|
||||||
_workBufferMemoryPin.Dispose();
|
_workBufferMemoryPin.Dispose();
|
||||||
_workBufferRegion.Dispose();
|
|
||||||
|
|
||||||
if (MemoryManager is IRefCounted rc)
|
if (MemoryManager is IRefCounted rc)
|
||||||
{
|
{
|
||||||
|
@@ -305,13 +305,34 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
/// <param name="workBufferSize">The guest work buffer size.</param>
|
/// <param name="workBufferSize">The guest work buffer size.</param>
|
||||||
/// <param name="processHandle">The process handle of the application.</param>
|
/// <param name="processHandle">The process handle of the application.</param>
|
||||||
/// <returns>A <see cref="ResultCode"/> reporting an error or a success.</returns>
|
/// <returns>A <see cref="ResultCode"/> reporting an error or a success.</returns>
|
||||||
public ResultCode OpenAudioRenderer(out AudioRenderSystem renderer, IVirtualMemoryManager memoryManager, ref AudioRendererConfiguration parameter, ulong appletResourceUserId, ulong workBufferAddress, ulong workBufferSize, uint processHandle, float volume)
|
public ResultCode OpenAudioRenderer(
|
||||||
|
out AudioRenderSystem renderer,
|
||||||
|
IVirtualMemoryManager memoryManager,
|
||||||
|
ref AudioRendererConfiguration parameter,
|
||||||
|
ulong appletResourceUserId,
|
||||||
|
ulong workBufferAddress,
|
||||||
|
ulong workBufferSize,
|
||||||
|
uint processHandle,
|
||||||
|
float volume)
|
||||||
{
|
{
|
||||||
int sessionId = AcquireSessionId();
|
int sessionId = AcquireSessionId();
|
||||||
|
|
||||||
AudioRenderSystem audioRenderer = new AudioRenderSystem(this, _sessionsSystemEvent[sessionId]);
|
AudioRenderSystem audioRenderer = new AudioRenderSystem(this, _sessionsSystemEvent[sessionId]);
|
||||||
|
|
||||||
ResultCode result = audioRenderer.Initialize(ref parameter, processHandle, workBufferAddress, workBufferSize, sessionId, appletResourceUserId, memoryManager);
|
// TODO: Eventually, we should try to use the guest supplied work buffer instead of allocating
|
||||||
|
// our own. However, it was causing problems on some applications that would unmap the memory
|
||||||
|
// before the audio renderer was fully disposed.
|
||||||
|
Memory<byte> workBufferMemory = GC.AllocateArray<byte>((int)workBufferSize, pinned: true);
|
||||||
|
|
||||||
|
ResultCode result = audioRenderer.Initialize(
|
||||||
|
ref parameter,
|
||||||
|
processHandle,
|
||||||
|
workBufferMemory,
|
||||||
|
workBufferAddress,
|
||||||
|
workBufferSize,
|
||||||
|
sessionId,
|
||||||
|
appletResourceUserId,
|
||||||
|
memoryManager);
|
||||||
|
|
||||||
if (result == ResultCode.Success)
|
if (result == ResultCode.Success)
|
||||||
{
|
{
|
||||||
|
@@ -5,10 +5,10 @@ namespace Ryujinx.Common.Collections
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class IntrusiveRedBlackTreeNode<T> where T : IntrusiveRedBlackTreeNode<T>
|
public class IntrusiveRedBlackTreeNode<T> where T : IntrusiveRedBlackTreeNode<T>
|
||||||
{
|
{
|
||||||
public bool Color = true;
|
internal bool Color = true;
|
||||||
public T Left;
|
internal T Left;
|
||||||
public T Right;
|
internal T Right;
|
||||||
public T Parent;
|
internal T Parent;
|
||||||
|
|
||||||
public T Predecessor => IntrusiveRedBlackTreeImpl<T>.PredecessorOf((T)this);
|
public T Predecessor => IntrusiveRedBlackTreeImpl<T>.PredecessorOf((T)this);
|
||||||
public T Successor => IntrusiveRedBlackTreeImpl<T>.SuccessorOf((T)this);
|
public T Successor => IntrusiveRedBlackTreeImpl<T>.SuccessorOf((T)this);
|
||||||
|
@@ -274,7 +274,8 @@ namespace Ryujinx.Cpu.Jit
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void Write(ulong va, ReadOnlySpan<byte> data)
|
public void Write(ulong va, ReadOnlySpan<byte> data)
|
||||||
{
|
{
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
SignalMemoryTracking(va, (ulong)data.Length, write: true);
|
SignalMemoryTracking(va, (ulong)data.Length, write: true);
|
||||||
|
|
||||||
_addressSpaceMirror.Write(va, data);
|
_addressSpaceMirror.Write(va, data);
|
||||||
|
@@ -26,6 +26,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
public readonly bool SupportsNonConstantTextureOffset;
|
public readonly bool SupportsNonConstantTextureOffset;
|
||||||
public readonly bool SupportsShaderBallot;
|
public readonly bool SupportsShaderBallot;
|
||||||
public readonly bool SupportsTextureShadowLod;
|
public readonly bool SupportsTextureShadowLod;
|
||||||
|
public readonly bool SupportsViewportIndex;
|
||||||
public readonly bool SupportsViewportSwizzle;
|
public readonly bool SupportsViewportSwizzle;
|
||||||
public readonly bool SupportsIndirectParameters;
|
public readonly bool SupportsIndirectParameters;
|
||||||
|
|
||||||
@@ -59,6 +60,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
bool supportsNonConstantTextureOffset,
|
bool supportsNonConstantTextureOffset,
|
||||||
bool supportsShaderBallot,
|
bool supportsShaderBallot,
|
||||||
bool supportsTextureShadowLod,
|
bool supportsTextureShadowLod,
|
||||||
|
bool supportsViewportIndex,
|
||||||
bool supportsViewportSwizzle,
|
bool supportsViewportSwizzle,
|
||||||
bool supportsIndirectParameters,
|
bool supportsIndirectParameters,
|
||||||
uint maximumUniformBuffersPerStage,
|
uint maximumUniformBuffersPerStage,
|
||||||
@@ -89,6 +91,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
SupportsNonConstantTextureOffset = supportsNonConstantTextureOffset;
|
SupportsNonConstantTextureOffset = supportsNonConstantTextureOffset;
|
||||||
SupportsShaderBallot = supportsShaderBallot;
|
SupportsShaderBallot = supportsShaderBallot;
|
||||||
SupportsTextureShadowLod = supportsTextureShadowLod;
|
SupportsTextureShadowLod = supportsTextureShadowLod;
|
||||||
|
SupportsViewportIndex = supportsViewportIndex;
|
||||||
SupportsViewportSwizzle = supportsViewportSwizzle;
|
SupportsViewportSwizzle = supportsViewportSwizzle;
|
||||||
SupportsIndirectParameters = supportsIndirectParameters;
|
SupportsIndirectParameters = supportsIndirectParameters;
|
||||||
MaximumUniformBuffersPerStage = maximumUniformBuffersPerStage;
|
MaximumUniformBuffersPerStage = maximumUniformBuffersPerStage;
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
{
|
{
|
||||||
@@ -151,10 +152,21 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
|
|
||||||
ulong ticks = _context.GetTimestamp();
|
ulong ticks = _context.GetTimestamp();
|
||||||
|
|
||||||
|
float divisor = type switch
|
||||||
|
{
|
||||||
|
ReportCounterType.SamplesPassed => _channel.TextureManager.RenderTargetScale * _channel.TextureManager.RenderTargetScale,
|
||||||
|
_ => 1f
|
||||||
|
};
|
||||||
|
|
||||||
ICounterEvent counter = null;
|
ICounterEvent counter = null;
|
||||||
|
|
||||||
void resultHandler(object evt, ulong result)
|
void resultHandler(object evt, ulong result)
|
||||||
{
|
{
|
||||||
|
if (divisor != 1f)
|
||||||
|
{
|
||||||
|
result = (ulong)MathF.Ceiling(result / divisor);
|
||||||
|
}
|
||||||
|
|
||||||
CounterData counterData = new CounterData
|
CounterData counterData = new CounterData
|
||||||
{
|
{
|
||||||
Counter = result,
|
Counter = result,
|
||||||
|
@@ -47,6 +47,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
|
|
||||||
public int TextureHandle;
|
public int TextureHandle;
|
||||||
public int SamplerHandle;
|
public int SamplerHandle;
|
||||||
|
public Format ImageFormat;
|
||||||
public int InvalidatedSequence;
|
public int InvalidatedSequence;
|
||||||
public Texture CachedTexture;
|
public Texture CachedTexture;
|
||||||
public Sampler CachedSampler;
|
public Sampler CachedSampler;
|
||||||
@@ -564,6 +565,9 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
// Buffers are frequently re-created to accomodate larger data, so we need to re-bind
|
// Buffers are frequently re-created to accomodate larger data, so we need to re-bind
|
||||||
// to ensure we're not using a old buffer that was already deleted.
|
// to ensure we're not using a old buffer that was already deleted.
|
||||||
_channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range.GetSubRange(0).Address, texture.Size, bindingInfo, bindingInfo.Format, false);
|
_channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range.GetSubRange(0).Address, texture.Size, bindingInfo, bindingInfo.Format, false);
|
||||||
|
|
||||||
|
// Cache is not used for buffer texture, it must always rebind.
|
||||||
|
state.CachedTexture = null;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -659,14 +663,16 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
cachedTexture?.SignalModified();
|
cachedTexture?.SignalModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((usageFlags & TextureUsageFlags.NeedsScaleValue) != 0 &&
|
Format format = bindingInfo.Format == 0 ? cachedTexture.Format : bindingInfo.Format;
|
||||||
UpdateScale(state.CachedTexture, usageFlags, scaleIndex, stage))
|
|
||||||
|
if (state.ImageFormat != format ||
|
||||||
|
((usageFlags & TextureUsageFlags.NeedsScaleValue) != 0 &&
|
||||||
|
UpdateScale(state.CachedTexture, usageFlags, scaleIndex, stage)))
|
||||||
{
|
{
|
||||||
ITexture hostTextureRebind = state.CachedTexture.GetTargetTexture(bindingInfo.Target);
|
ITexture hostTextureRebind = state.CachedTexture.GetTargetTexture(bindingInfo.Target);
|
||||||
|
|
||||||
Format format = bindingInfo.Format == 0 ? cachedTexture.Format : bindingInfo.Format;
|
|
||||||
|
|
||||||
state.Texture = hostTextureRebind;
|
state.Texture = hostTextureRebind;
|
||||||
|
state.ImageFormat = format;
|
||||||
|
|
||||||
_context.Renderer.Pipeline.SetImage(bindingInfo.Binding, hostTextureRebind, format);
|
_context.Renderer.Pipeline.SetImage(bindingInfo.Binding, hostTextureRebind, format);
|
||||||
}
|
}
|
||||||
@@ -696,6 +702,9 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
}
|
}
|
||||||
|
|
||||||
_channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range.GetSubRange(0).Address, texture.Size, bindingInfo, format, true);
|
_channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range.GetSubRange(0).Address, texture.Size, bindingInfo, format, true);
|
||||||
|
|
||||||
|
// Cache is not used for buffer texture, it must always rebind.
|
||||||
|
state.CachedTexture = null;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -721,6 +730,8 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
format = texture.Format;
|
format = texture.Format;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state.ImageFormat = format;
|
||||||
|
|
||||||
_context.Renderer.Pipeline.SetImage(bindingInfo.Binding, hostTexture, format);
|
_context.Renderer.Pipeline.SetImage(bindingInfo.Binding, hostTexture, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
private const ushort FileFormatVersionMajor = 1;
|
private const ushort FileFormatVersionMajor = 1;
|
||||||
private const ushort FileFormatVersionMinor = 2;
|
private const ushort FileFormatVersionMinor = 2;
|
||||||
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
||||||
private const uint CodeGenVersion = 3672;
|
private const uint CodeGenVersion = 3644;
|
||||||
|
|
||||||
private const string SharedTocFileName = "shared.toc";
|
private const string SharedTocFileName = "shared.toc";
|
||||||
private const string SharedDataFileName = "shared.data";
|
private const string SharedDataFileName = "shared.data";
|
||||||
@@ -827,4 +827,4 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -134,6 +134,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
|
|
||||||
public bool QueryHostSupportsTextureShadowLod() => _context.Capabilities.SupportsTextureShadowLod;
|
public bool QueryHostSupportsTextureShadowLod() => _context.Capabilities.SupportsTextureShadowLod;
|
||||||
|
|
||||||
|
public bool QueryHostSupportsViewportIndex() => _context.Capabilities.SupportsViewportIndex;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converts a packed Maxwell texture format to the shader translator texture format.
|
/// Converts a packed Maxwell texture format to the shader translator texture format.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@@ -120,6 +120,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
supportsNonConstantTextureOffset: HwCapabilities.SupportsNonConstantTextureOffset,
|
supportsNonConstantTextureOffset: HwCapabilities.SupportsNonConstantTextureOffset,
|
||||||
supportsShaderBallot: HwCapabilities.SupportsShaderBallot,
|
supportsShaderBallot: HwCapabilities.SupportsShaderBallot,
|
||||||
supportsTextureShadowLod: HwCapabilities.SupportsTextureShadowLod,
|
supportsTextureShadowLod: HwCapabilities.SupportsTextureShadowLod,
|
||||||
|
supportsViewportIndex: true,
|
||||||
supportsViewportSwizzle: HwCapabilities.SupportsViewportSwizzle,
|
supportsViewportSwizzle: HwCapabilities.SupportsViewportSwizzle,
|
||||||
supportsIndirectParameters: HwCapabilities.SupportsIndirectParameters,
|
supportsIndirectParameters: HwCapabilities.SupportsIndirectParameters,
|
||||||
maximumUniformBuffersPerStage: 13, // TODO: Avoid hardcoding those limits here and get from driver?
|
maximumUniformBuffersPerStage: 13, // TODO: Avoid hardcoding those limits here and get from driver?
|
||||||
|
@@ -267,6 +267,15 @@ namespace Ryujinx.Graphics.Shader
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queries host GPU shader viewport index output support.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if the GPU and driver supports shader viewport index output, false otherwise</returns>
|
||||||
|
bool QueryHostSupportsViewportIndex()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Queries the point size from the GPU state, used when it is not explicitly set on the shader.
|
/// Queries the point size from the GPU state, used when it is not explicitly set on the shader.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@@ -78,6 +78,11 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
|
|
||||||
public static bool Validate(ShaderConfig config, int value, bool isOutAttr)
|
public static bool Validate(ShaderConfig config, int value, bool isOutAttr)
|
||||||
{
|
{
|
||||||
|
if (value == AttributeConsts.ViewportIndex && !config.GpuAccessor.QueryHostSupportsViewportIndex())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return From(config, value, isOutAttr).IsValid;
|
return From(config, value, isOutAttr).IsValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -108,6 +108,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
format = VkFormat.D32SfloatS8Uint;
|
format = VkFormat.D32SfloatS8Uint;
|
||||||
}
|
}
|
||||||
|
else if (srcFormat == GAL.Format.R4G4B4A4Unorm)
|
||||||
|
{
|
||||||
|
format = VkFormat.R4G4B4A4UnormPack16;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger.Error?.Print(LogClass.Gpu, $"Format {srcFormat} is not supported by the host.");
|
Logger.Error?.Print(LogClass.Gpu, $"Format {srcFormat} is not supported by the host.");
|
||||||
|
@@ -6,11 +6,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
static class FormatTable
|
static class FormatTable
|
||||||
{
|
{
|
||||||
private static readonly VkFormat[] Table;
|
private static readonly VkFormat[] _table;
|
||||||
|
|
||||||
static FormatTable()
|
static FormatTable()
|
||||||
{
|
{
|
||||||
Table = new VkFormat[Enum.GetNames(typeof(Format)).Length];
|
_table = new VkFormat[Enum.GetNames(typeof(Format)).Length];
|
||||||
|
|
||||||
Add(Format.R8Unorm, VkFormat.R8Unorm);
|
Add(Format.R8Unorm, VkFormat.R8Unorm);
|
||||||
Add(Format.R8Snorm, VkFormat.R8SNorm);
|
Add(Format.R8Snorm, VkFormat.R8SNorm);
|
||||||
@@ -68,7 +68,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
Add(Format.D32FloatS8Uint, VkFormat.D32SfloatS8Uint);
|
Add(Format.D32FloatS8Uint, VkFormat.D32SfloatS8Uint);
|
||||||
Add(Format.R8G8B8A8Srgb, VkFormat.R8G8B8A8Srgb);
|
Add(Format.R8G8B8A8Srgb, VkFormat.R8G8B8A8Srgb);
|
||||||
Add(Format.R4G4Unorm, VkFormat.R4G4UnormPack8);
|
Add(Format.R4G4Unorm, VkFormat.R4G4UnormPack8);
|
||||||
Add(Format.R4G4B4A4Unorm, VkFormat.R4G4B4A4UnormPack16);
|
Add(Format.R4G4B4A4Unorm, VkFormat.A4B4G4R4UnormPack16Ext);
|
||||||
Add(Format.R5G5B5X1Unorm, VkFormat.A1R5G5B5UnormPack16);
|
Add(Format.R5G5B5X1Unorm, VkFormat.A1R5G5B5UnormPack16);
|
||||||
Add(Format.R5G5B5A1Unorm, VkFormat.A1R5G5B5UnormPack16);
|
Add(Format.R5G5B5A1Unorm, VkFormat.A1R5G5B5UnormPack16);
|
||||||
Add(Format.R5G6B5Unorm, VkFormat.R5G6B5UnormPack16);
|
Add(Format.R5G6B5Unorm, VkFormat.R5G6B5UnormPack16);
|
||||||
@@ -161,12 +161,12 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
private static void Add(Format format, VkFormat vkFormat)
|
private static void Add(Format format, VkFormat vkFormat)
|
||||||
{
|
{
|
||||||
Table[(int)format] = vkFormat;
|
_table[(int)format] = vkFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static VkFormat GetFormat(Format format)
|
public static VkFormat GetFormat(Format format)
|
||||||
{
|
{
|
||||||
return Table[(int)format];
|
return _table[(int)format];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -74,17 +74,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
swizzleR = swizzleB;
|
swizzleR = swizzleB;
|
||||||
swizzleB = temp;
|
swizzleB = temp;
|
||||||
}
|
}
|
||||||
else if (info.Format == GAL.Format.R4G4B4A4Unorm)
|
else if (VkFormat == VkFormat.R4G4B4A4UnormPack16 || info.Format == GAL.Format.A1B5G5R5Unorm)
|
||||||
{
|
|
||||||
var tempG = swizzleG;
|
|
||||||
var tempB = swizzleB;
|
|
||||||
|
|
||||||
swizzleB = swizzleA;
|
|
||||||
swizzleG = swizzleR;
|
|
||||||
swizzleR = tempG;
|
|
||||||
swizzleA = tempB;
|
|
||||||
}
|
|
||||||
else if (info.Format == GAL.Format.A1B5G5R5Unorm)
|
|
||||||
{
|
{
|
||||||
var tempB = swizzleB;
|
var tempB = swizzleB;
|
||||||
var tempA = swizzleA;
|
var tempA = swizzleA;
|
||||||
|
@@ -380,7 +380,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
return BufferManager.GetData(buffer, offset, size);
|
return BufferManager.GetData(buffer, offset, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Capabilities GetCapabilities()
|
public unsafe Capabilities GetCapabilities()
|
||||||
{
|
{
|
||||||
FormatFeatureFlags compressedFormatFeatureFlags =
|
FormatFeatureFlags compressedFormatFeatureFlags =
|
||||||
FormatFeatureFlags.FormatFeatureSampledImageBit |
|
FormatFeatureFlags.FormatFeatureSampledImageBit |
|
||||||
@@ -409,7 +409,19 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
GAL.Format.Bc7Srgb,
|
GAL.Format.Bc7Srgb,
|
||||||
GAL.Format.Bc7Unorm);
|
GAL.Format.Bc7Unorm);
|
||||||
|
|
||||||
Api.GetPhysicalDeviceFeatures(_physicalDevice, out var features);
|
|
||||||
|
PhysicalDeviceVulkan12Features featuresVk12 = new PhysicalDeviceVulkan12Features()
|
||||||
|
{
|
||||||
|
SType = StructureType.PhysicalDeviceVulkan12Features
|
||||||
|
};
|
||||||
|
|
||||||
|
PhysicalDeviceFeatures2 features2 = new PhysicalDeviceFeatures2()
|
||||||
|
{
|
||||||
|
SType = StructureType.PhysicalDeviceFeatures2,
|
||||||
|
PNext = &featuresVk12
|
||||||
|
};
|
||||||
|
|
||||||
|
Api.GetPhysicalDeviceFeatures2(_physicalDevice, &features2);
|
||||||
Api.GetPhysicalDeviceProperties(_physicalDevice, out var properties);
|
Api.GetPhysicalDeviceProperties(_physicalDevice, out var properties);
|
||||||
|
|
||||||
var limits = properties.Limits;
|
var limits = properties.Limits;
|
||||||
@@ -419,7 +431,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
GpuVendor,
|
GpuVendor,
|
||||||
hasFrontFacingBug: IsIntelWindows,
|
hasFrontFacingBug: IsIntelWindows,
|
||||||
hasVectorIndexingBug: Vendor == Vendor.Qualcomm,
|
hasVectorIndexingBug: Vendor == Vendor.Qualcomm,
|
||||||
supportsAstcCompression: features.TextureCompressionAstcLdr,
|
supportsAstcCompression: features2.Features.TextureCompressionAstcLdr,
|
||||||
supportsBc123Compression: supportsBc123CompressionFormat,
|
supportsBc123Compression: supportsBc123CompressionFormat,
|
||||||
supportsBc45Compression: supportsBc45CompressionFormat,
|
supportsBc45Compression: supportsBc45CompressionFormat,
|
||||||
supportsBc67Compression: supportsBc67CompressionFormat,
|
supportsBc67Compression: supportsBc67CompressionFormat,
|
||||||
@@ -429,12 +441,13 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
supportsFragmentShaderInterlock: Capabilities.SupportsFragmentShaderInterlock,
|
supportsFragmentShaderInterlock: Capabilities.SupportsFragmentShaderInterlock,
|
||||||
supportsFragmentShaderOrderingIntel: false,
|
supportsFragmentShaderOrderingIntel: false,
|
||||||
supportsGeometryShaderPassthrough: Capabilities.SupportsGeometryShaderPassthrough,
|
supportsGeometryShaderPassthrough: Capabilities.SupportsGeometryShaderPassthrough,
|
||||||
supportsImageLoadFormatted: features.ShaderStorageImageReadWithoutFormat,
|
supportsImageLoadFormatted: features2.Features.ShaderStorageImageReadWithoutFormat,
|
||||||
supportsMismatchingViewFormat: true,
|
supportsMismatchingViewFormat: true,
|
||||||
supportsCubemapView: !IsAmdGcn,
|
supportsCubemapView: !IsAmdGcn,
|
||||||
supportsNonConstantTextureOffset: false,
|
supportsNonConstantTextureOffset: false,
|
||||||
supportsShaderBallot: false,
|
supportsShaderBallot: false,
|
||||||
supportsTextureShadowLod: false,
|
supportsTextureShadowLod: false,
|
||||||
|
supportsViewportIndex: featuresVk12.ShaderOutputViewportIndex,
|
||||||
supportsViewportSwizzle: false,
|
supportsViewportSwizzle: false,
|
||||||
supportsIndirectParameters: Capabilities.SupportsIndirectParameters,
|
supportsIndirectParameters: Capabilities.SupportsIndirectParameters,
|
||||||
maximumUniformBuffersPerStage: Constants.MaxUniformBuffersPerStage,
|
maximumUniformBuffersPerStage: Constants.MaxUniformBuffersPerStage,
|
||||||
|
@@ -31,11 +31,26 @@ namespace Ryujinx.HLE.HOS.Services.Audio
|
|||||||
return AudioRendererManagerImpl.GetWorkBufferSize(ref parameter);
|
return AudioRendererManagerImpl.GetWorkBufferSize(ref parameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResultCode OpenAudioRenderer(ServiceCtx context, out IAudioRenderer obj, ref AudioRendererConfiguration parameter, ulong workBufferSize, ulong appletResourceUserId, KTransferMemory workBufferTransferMemory, uint processHandle)
|
public ResultCode OpenAudioRenderer(
|
||||||
|
ServiceCtx context,
|
||||||
|
out IAudioRenderer obj,
|
||||||
|
ref AudioRendererConfiguration parameter,
|
||||||
|
ulong workBufferSize,
|
||||||
|
ulong appletResourceUserId,
|
||||||
|
KTransferMemory workBufferTransferMemory,
|
||||||
|
uint processHandle)
|
||||||
{
|
{
|
||||||
var memoryManager = context.Process.HandleTable.GetKProcess((int)processHandle).CpuMemory;
|
var memoryManager = context.Process.HandleTable.GetKProcess((int)processHandle).CpuMemory;
|
||||||
|
|
||||||
ResultCode result = (ResultCode)_impl.OpenAudioRenderer(out AudioRenderSystem renderer, memoryManager, ref parameter, appletResourceUserId, workBufferTransferMemory.Address, workBufferTransferMemory.Size, processHandle, context.Device.Configuration.AudioVolume);
|
ResultCode result = (ResultCode)_impl.OpenAudioRenderer(
|
||||||
|
out AudioRenderSystem renderer,
|
||||||
|
memoryManager,
|
||||||
|
ref parameter,
|
||||||
|
appletResourceUserId,
|
||||||
|
workBufferTransferMemory.Address,
|
||||||
|
workBufferTransferMemory.Size,
|
||||||
|
processHandle,
|
||||||
|
context.Device.Configuration.AudioVolume);
|
||||||
|
|
||||||
if (result == ResultCode.Success)
|
if (result == ResultCode.Success)
|
||||||
{
|
{
|
||||||
|
@@ -34,7 +34,14 @@ namespace Ryujinx.HLE.HOS.Services.Audio
|
|||||||
KTransferMemory workBufferTransferMemory = context.Process.HandleTable.GetObject<KTransferMemory>(transferMemoryHandle);
|
KTransferMemory workBufferTransferMemory = context.Process.HandleTable.GetObject<KTransferMemory>(transferMemoryHandle);
|
||||||
uint processHandle = (uint)context.Request.HandleDesc.ToCopy[1];
|
uint processHandle = (uint)context.Request.HandleDesc.ToCopy[1];
|
||||||
|
|
||||||
ResultCode result = _impl.OpenAudioRenderer(context, out IAudioRenderer renderer, ref parameter, workBufferSize, appletResourceUserId, workBufferTransferMemory, processHandle);
|
ResultCode result = _impl.OpenAudioRenderer(
|
||||||
|
context,
|
||||||
|
out IAudioRenderer renderer,
|
||||||
|
ref parameter,
|
||||||
|
workBufferSize,
|
||||||
|
appletResourceUserId,
|
||||||
|
workBufferTransferMemory,
|
||||||
|
processHandle);
|
||||||
|
|
||||||
if (result == ResultCode.Success)
|
if (result == ResultCode.Success)
|
||||||
{
|
{
|
||||||
|
@@ -1,453 +0,0 @@
|
|||||||
using Ryujinx.Common.Collections;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Ryujinx.Memory.WindowsShared
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// An Augmented Interval Tree based off of the "TreeDictionary"'s Red-Black Tree. Allows fast overlap checking of ranges.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="K">Key</typeparam>
|
|
||||||
/// <typeparam name="V">Value</typeparam>
|
|
||||||
class IntervalTree<K, V> : IntrusiveRedBlackTreeImpl<IntervalTreeNode<K, V>> where K : IComparable<K>
|
|
||||||
{
|
|
||||||
private const int ArrayGrowthSize = 32;
|
|
||||||
|
|
||||||
#region Public Methods
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the values of the interval whose key is <paramref name="key"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="key">Key of the node value to get</param>
|
|
||||||
/// <param name="value">Value with the given <paramref name="key"/></param>
|
|
||||||
/// <returns>True if the key is on the dictionary, false otherwise</returns>
|
|
||||||
public bool TryGet(K key, out V value)
|
|
||||||
{
|
|
||||||
IntervalTreeNode<K, V> node = GetNode(key);
|
|
||||||
|
|
||||||
if (node == null)
|
|
||||||
{
|
|
||||||
value = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = node.Value;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the start addresses of the intervals whose start and end keys overlap the given range.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="start">Start of the range</param>
|
|
||||||
/// <param name="end">End of the range</param>
|
|
||||||
/// <param name="overlaps">Overlaps array to place results in</param>
|
|
||||||
/// <param name="overlapCount">Index to start writing results into the array. Defaults to 0</param>
|
|
||||||
/// <returns>Number of intervals found</returns>
|
|
||||||
public int Get(K start, K end, ref IntervalTreeNode<K, V>[] overlaps, int overlapCount = 0)
|
|
||||||
{
|
|
||||||
GetNodes(Root, start, end, ref overlaps, ref overlapCount);
|
|
||||||
|
|
||||||
return overlapCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds a new interval into the tree whose start is <paramref name="start"/>, end is <paramref name="end"/> and value is <paramref name="value"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="start">Start of the range to add</param>
|
|
||||||
/// <param name="end">End of the range to insert</param>
|
|
||||||
/// <param name="value">Value to add</param>
|
|
||||||
/// <exception cref="ArgumentNullException"><paramref name="value"/> is null</exception>
|
|
||||||
public void Add(K start, K end, V value)
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
BSTInsert(start, end, value, null, out _);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes a value from the tree, searching for it with <paramref name="key"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="key">Key of the node to remove</param>
|
|
||||||
/// <returns>Number of deleted values</returns>
|
|
||||||
public int Remove(K key)
|
|
||||||
{
|
|
||||||
return Remove(GetNode(key));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes a value from the tree, searching for it with <paramref name="key"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="nodeToDelete">Node to be removed</param>
|
|
||||||
/// <returns>Number of deleted values</returns>
|
|
||||||
public int Remove(IntervalTreeNode<K, V> nodeToDelete)
|
|
||||||
{
|
|
||||||
if (nodeToDelete == null)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Delete(nodeToDelete);
|
|
||||||
|
|
||||||
Count--;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds all the nodes in the dictionary into <paramref name="list"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A list of all values sorted by Key Order</returns>
|
|
||||||
public List<V> AsList()
|
|
||||||
{
|
|
||||||
List<V> list = new List<V>();
|
|
||||||
|
|
||||||
AddToList(Root, list);
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Private Methods (BST)
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds all values that are children of or contained within <paramref name="node"/> into <paramref name="list"/>, in Key Order.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="node">The node to search for values within</param>
|
|
||||||
/// <param name="list">The list to add values to</param>
|
|
||||||
private void AddToList(IntervalTreeNode<K, V> node, List<V> list)
|
|
||||||
{
|
|
||||||
if (node == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
AddToList(node.Left, list);
|
|
||||||
|
|
||||||
list.Add(node.Value);
|
|
||||||
|
|
||||||
AddToList(node.Right, list);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Retrieve the node reference whose key is <paramref name="key"/>, or null if no such node exists.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="key">Key of the node to get</param>
|
|
||||||
/// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
|
|
||||||
/// <returns>Node reference in the tree</returns>
|
|
||||||
private IntervalTreeNode<K, V> GetNode(K key)
|
|
||||||
{
|
|
||||||
if (key == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(key));
|
|
||||||
}
|
|
||||||
|
|
||||||
IntervalTreeNode<K, V> node = Root;
|
|
||||||
while (node != null)
|
|
||||||
{
|
|
||||||
int cmp = key.CompareTo(node.Start);
|
|
||||||
if (cmp < 0)
|
|
||||||
{
|
|
||||||
node = node.Left;
|
|
||||||
}
|
|
||||||
else if (cmp > 0)
|
|
||||||
{
|
|
||||||
node = node.Right;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Retrieve all nodes that overlap the given start and end keys.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="start">Start of the range</param>
|
|
||||||
/// <param name="end">End of the range</param>
|
|
||||||
/// <param name="overlaps">Overlaps array to place results in</param>
|
|
||||||
/// <param name="overlapCount">Overlaps count to update</param>
|
|
||||||
private void GetNodes(IntervalTreeNode<K, V> node, K start, K end, ref IntervalTreeNode<K, V>[] overlaps, ref int overlapCount)
|
|
||||||
{
|
|
||||||
if (node == null || start.CompareTo(node.Max) >= 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
GetNodes(node.Left, start, end, ref overlaps, ref overlapCount);
|
|
||||||
|
|
||||||
bool endsOnRight = end.CompareTo(node.Start) > 0;
|
|
||||||
if (endsOnRight)
|
|
||||||
{
|
|
||||||
if (start.CompareTo(node.End) < 0)
|
|
||||||
{
|
|
||||||
if (overlaps.Length >= overlapCount)
|
|
||||||
{
|
|
||||||
Array.Resize(ref overlaps, overlapCount + ArrayGrowthSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
overlaps[overlapCount++] = node;
|
|
||||||
}
|
|
||||||
|
|
||||||
GetNodes(node.Right, start, end, ref overlaps, ref overlapCount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Propagate an increase in max value starting at the given node, heading up the tree.
|
|
||||||
/// This should only be called if the max increases - not for rebalancing or removals.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="node">The node to start propagating from</param>
|
|
||||||
private void PropagateIncrease(IntervalTreeNode<K, V> node)
|
|
||||||
{
|
|
||||||
K max = node.Max;
|
|
||||||
IntervalTreeNode<K, V> ptr = node;
|
|
||||||
|
|
||||||
while ((ptr = ptr.Parent) != null)
|
|
||||||
{
|
|
||||||
if (max.CompareTo(ptr.Max) > 0)
|
|
||||||
{
|
|
||||||
ptr.Max = max;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Propagate recalculating max value starting at the given node, heading up the tree.
|
|
||||||
/// This fully recalculates the max value from all children when there is potential for it to decrease.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="node">The node to start propagating from</param>
|
|
||||||
private void PropagateFull(IntervalTreeNode<K, V> node)
|
|
||||||
{
|
|
||||||
IntervalTreeNode<K, V> ptr = node;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
K max = ptr.End;
|
|
||||||
|
|
||||||
if (ptr.Left != null && ptr.Left.Max.CompareTo(max) > 0)
|
|
||||||
{
|
|
||||||
max = ptr.Left.Max;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ptr.Right != null && ptr.Right.Max.CompareTo(max) > 0)
|
|
||||||
{
|
|
||||||
max = ptr.Right.Max;
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr.Max = max;
|
|
||||||
} while ((ptr = ptr.Parent) != null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Insertion Mechanism for the interval tree. Similar to a BST insert, with the start of the range as the key.
|
|
||||||
/// Iterates the tree starting from the root and inserts a new node where all children in the left subtree are less than <paramref name="start"/>, and all children in the right subtree are greater than <paramref name="start"/>.
|
|
||||||
/// Each node can contain multiple values, and has an end address which is the maximum of all those values.
|
|
||||||
/// Post insertion, the "max" value of the node and all parents are updated.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="start">Start of the range to insert</param>
|
|
||||||
/// <param name="end">End of the range to insert</param>
|
|
||||||
/// <param name="value">Value to insert</param>
|
|
||||||
/// <param name="updateFactoryCallback">Optional factory used to create a new value if <paramref name="start"/> is already on the tree</param>
|
|
||||||
/// <param name="outNode">Node that was inserted or modified</param>
|
|
||||||
/// <returns>True if <paramref name="start"/> was not yet on the tree, false otherwise</returns>
|
|
||||||
private bool BSTInsert(K start, K end, V value, Func<K, V, V> updateFactoryCallback, out IntervalTreeNode<K, V> outNode)
|
|
||||||
{
|
|
||||||
IntervalTreeNode<K, V> parent = null;
|
|
||||||
IntervalTreeNode<K, V> node = Root;
|
|
||||||
|
|
||||||
while (node != null)
|
|
||||||
{
|
|
||||||
parent = node;
|
|
||||||
int cmp = start.CompareTo(node.Start);
|
|
||||||
if (cmp < 0)
|
|
||||||
{
|
|
||||||
node = node.Left;
|
|
||||||
}
|
|
||||||
else if (cmp > 0)
|
|
||||||
{
|
|
||||||
node = node.Right;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
outNode = node;
|
|
||||||
|
|
||||||
if (updateFactoryCallback != null)
|
|
||||||
{
|
|
||||||
// Replace
|
|
||||||
node.Value = updateFactoryCallback(start, node.Value);
|
|
||||||
|
|
||||||
int endCmp = end.CompareTo(node.End);
|
|
||||||
|
|
||||||
if (endCmp > 0)
|
|
||||||
{
|
|
||||||
node.End = end;
|
|
||||||
if (end.CompareTo(node.Max) > 0)
|
|
||||||
{
|
|
||||||
node.Max = end;
|
|
||||||
PropagateIncrease(node);
|
|
||||||
RestoreBalanceAfterInsertion(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (endCmp < 0)
|
|
||||||
{
|
|
||||||
node.End = end;
|
|
||||||
PropagateFull(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
IntervalTreeNode<K, V> newNode = new IntervalTreeNode<K, V>(start, end, value, parent);
|
|
||||||
if (newNode.Parent == null)
|
|
||||||
{
|
|
||||||
Root = newNode;
|
|
||||||
}
|
|
||||||
else if (start.CompareTo(parent.Start) < 0)
|
|
||||||
{
|
|
||||||
parent.Left = newNode;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
parent.Right = newNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
PropagateIncrease(newNode);
|
|
||||||
Count++;
|
|
||||||
RestoreBalanceAfterInsertion(newNode);
|
|
||||||
outNode = newNode;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes the value from the dictionary after searching for it with <paramref name="key">.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="key">Tree node to be removed</param>
|
|
||||||
private void Delete(IntervalTreeNode<K, V> nodeToDelete)
|
|
||||||
{
|
|
||||||
IntervalTreeNode<K, V> replacementNode;
|
|
||||||
|
|
||||||
if (LeftOf(nodeToDelete) == null || RightOf(nodeToDelete) == null)
|
|
||||||
{
|
|
||||||
replacementNode = nodeToDelete;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
replacementNode = nodeToDelete.Predecessor;
|
|
||||||
}
|
|
||||||
|
|
||||||
IntervalTreeNode<K, V> tmp = LeftOf(replacementNode) ?? RightOf(replacementNode);
|
|
||||||
|
|
||||||
if (tmp != null)
|
|
||||||
{
|
|
||||||
tmp.Parent = ParentOf(replacementNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ParentOf(replacementNode) == null)
|
|
||||||
{
|
|
||||||
Root = tmp;
|
|
||||||
}
|
|
||||||
else if (replacementNode == LeftOf(ParentOf(replacementNode)))
|
|
||||||
{
|
|
||||||
ParentOf(replacementNode).Left = tmp;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ParentOf(replacementNode).Right = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (replacementNode != nodeToDelete)
|
|
||||||
{
|
|
||||||
nodeToDelete.Start = replacementNode.Start;
|
|
||||||
nodeToDelete.Value = replacementNode.Value;
|
|
||||||
nodeToDelete.End = replacementNode.End;
|
|
||||||
nodeToDelete.Max = replacementNode.Max;
|
|
||||||
}
|
|
||||||
|
|
||||||
PropagateFull(replacementNode);
|
|
||||||
|
|
||||||
if (tmp != null && ColorOf(replacementNode) == Black)
|
|
||||||
{
|
|
||||||
RestoreBalanceAfterRemoval(tmp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Private Methods (RBL)
|
|
||||||
|
|
||||||
protected override void RotateLeft(IntervalTreeNode<K, V> node)
|
|
||||||
{
|
|
||||||
if (node != null)
|
|
||||||
{
|
|
||||||
base.RotateLeft(node);
|
|
||||||
|
|
||||||
PropagateFull(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void RotateRight(IntervalTreeNode<K, V> node)
|
|
||||||
{
|
|
||||||
if (node != null)
|
|
||||||
{
|
|
||||||
base.RotateRight(node);
|
|
||||||
|
|
||||||
PropagateFull(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
public bool ContainsKey(K key)
|
|
||||||
{
|
|
||||||
return GetNode(key) != null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a node in the IntervalTree which contains start and end keys of type K, and a value of generic type V.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="K">Key type of the node</typeparam>
|
|
||||||
/// <typeparam name="V">Value type of the node</typeparam>
|
|
||||||
class IntervalTreeNode<K, V> : IntrusiveRedBlackTreeNode<IntervalTreeNode<K, V>>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The start of the range.
|
|
||||||
/// </summary>
|
|
||||||
public K Start;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The end of the range.
|
|
||||||
/// </summary>
|
|
||||||
public K End;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The maximum end value of this node and all its children.
|
|
||||||
/// </summary>
|
|
||||||
public K Max;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Value stored on this node.
|
|
||||||
/// </summary>
|
|
||||||
public V Value;
|
|
||||||
|
|
||||||
public IntervalTreeNode(K start, K end, V value, IntervalTreeNode<K, V> parent)
|
|
||||||
{
|
|
||||||
Start = start;
|
|
||||||
End = end;
|
|
||||||
Max = end;
|
|
||||||
Value = value;
|
|
||||||
Parent = parent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
87
Ryujinx.Memory/WindowsShared/MappingTree.cs
Normal file
87
Ryujinx.Memory/WindowsShared/MappingTree.cs
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
using Ryujinx.Common.Collections;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Memory.WindowsShared
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A intrusive Red-Black Tree that also supports getting nodes overlapping a given range.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">Type of the value stored on the node</typeparam>
|
||||||
|
class MappingTree<T> : IntrusiveRedBlackTree<RangeNode<T>>
|
||||||
|
{
|
||||||
|
private const int ArrayGrowthSize = 16;
|
||||||
|
|
||||||
|
public int GetNodes(ulong start, ulong end, ref RangeNode<T>[] overlaps, int overlapCount = 0)
|
||||||
|
{
|
||||||
|
RangeNode<T> node = this.GetNodeByKey(start);
|
||||||
|
|
||||||
|
for (; node != null; node = node.Successor)
|
||||||
|
{
|
||||||
|
if (overlaps.Length <= overlapCount)
|
||||||
|
{
|
||||||
|
Array.Resize(ref overlaps, overlapCount + ArrayGrowthSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
overlaps[overlapCount++] = node;
|
||||||
|
|
||||||
|
if (node.End >= end)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return overlapCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RangeNode<T> : IntrusiveRedBlackTreeNode<RangeNode<T>>, IComparable<RangeNode<T>>, IComparable<ulong>
|
||||||
|
{
|
||||||
|
public ulong Start { get; }
|
||||||
|
public ulong End { get; private set; }
|
||||||
|
public T Value { get; }
|
||||||
|
|
||||||
|
public RangeNode(ulong start, ulong end, T value)
|
||||||
|
{
|
||||||
|
Start = start;
|
||||||
|
End = end;
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Extend(ulong sizeDelta)
|
||||||
|
{
|
||||||
|
End += sizeDelta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CompareTo(RangeNode<T> other)
|
||||||
|
{
|
||||||
|
if (Start < other.Start)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if (Start <= other.End - 1UL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CompareTo(ulong address)
|
||||||
|
{
|
||||||
|
if (address < Start)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (address <= End - 1UL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,3 +1,4 @@
|
|||||||
|
using Ryujinx.Common.Collections;
|
||||||
using Ryujinx.Common.Memory.PartialUnmaps;
|
using Ryujinx.Common.Memory.PartialUnmaps;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
@@ -13,10 +14,10 @@ namespace Ryujinx.Memory.WindowsShared
|
|||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
class PlaceholderManager
|
class PlaceholderManager
|
||||||
{
|
{
|
||||||
private const ulong MinimumPageSize = 0x1000;
|
private const int InitialOverlapsSize = 10;
|
||||||
|
|
||||||
private readonly IntervalTree<ulong, ulong> _mappings;
|
private readonly MappingTree<ulong> _mappings;
|
||||||
private readonly IntervalTree<ulong, MemoryPermission> _protections;
|
private readonly MappingTree<MemoryPermission> _protections;
|
||||||
private readonly IntPtr _partialUnmapStatePtr;
|
private readonly IntPtr _partialUnmapStatePtr;
|
||||||
private readonly Thread _partialUnmapTrimThread;
|
private readonly Thread _partialUnmapTrimThread;
|
||||||
|
|
||||||
@@ -25,8 +26,8 @@ namespace Ryujinx.Memory.WindowsShared
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public PlaceholderManager()
|
public PlaceholderManager()
|
||||||
{
|
{
|
||||||
_mappings = new IntervalTree<ulong, ulong>();
|
_mappings = new MappingTree<ulong>();
|
||||||
_protections = new IntervalTree<ulong, MemoryPermission>();
|
_protections = new MappingTree<MemoryPermission>();
|
||||||
|
|
||||||
_partialUnmapStatePtr = PartialUnmapState.GlobalState;
|
_partialUnmapStatePtr = PartialUnmapState.GlobalState;
|
||||||
|
|
||||||
@@ -67,7 +68,12 @@ namespace Ryujinx.Memory.WindowsShared
|
|||||||
{
|
{
|
||||||
lock (_mappings)
|
lock (_mappings)
|
||||||
{
|
{
|
||||||
_mappings.Add(address, address + size, ulong.MaxValue);
|
_mappings.Add(new RangeNode<ulong>(address, address + size, ulong.MaxValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (_protections)
|
||||||
|
{
|
||||||
|
_protections.Add(new RangeNode<MemoryPermission>(address, size, MemoryPermission.None));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,35 +87,30 @@ namespace Ryujinx.Memory.WindowsShared
|
|||||||
{
|
{
|
||||||
ulong endAddress = address + size;
|
ulong endAddress = address + size;
|
||||||
|
|
||||||
var overlaps = Array.Empty<IntervalTreeNode<ulong, ulong>>();
|
|
||||||
int count;
|
|
||||||
|
|
||||||
lock (_mappings)
|
lock (_mappings)
|
||||||
{
|
{
|
||||||
count = _mappings.Get(address, endAddress, ref overlaps);
|
RangeNode<ulong> node = _mappings.GetNodeByKey(address);
|
||||||
|
RangeNode<ulong> successorNode;
|
||||||
|
|
||||||
for (int index = 0; index < count; index++)
|
for (; node != null; node = successorNode)
|
||||||
{
|
{
|
||||||
var overlap = overlaps[index];
|
successorNode = node.Successor;
|
||||||
|
|
||||||
if (IsMapped(overlap.Value))
|
if (IsMapped(node.Value))
|
||||||
{
|
{
|
||||||
if (!WindowsApi.UnmapViewOfFile2(WindowsApi.CurrentProcessHandle, (IntPtr)overlap.Start, 2))
|
if (!WindowsApi.UnmapViewOfFile2(WindowsApi.CurrentProcessHandle, (IntPtr)node.Start, 2))
|
||||||
{
|
{
|
||||||
throw new WindowsApiException("UnmapViewOfFile2");
|
throw new WindowsApiException("UnmapViewOfFile2");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_mappings.Remove(overlap);
|
_mappings.Remove(node);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count > 1)
|
if (node.End >= endAddress)
|
||||||
{
|
{
|
||||||
CheckFreeResult(WindowsApi.VirtualFree(
|
break;
|
||||||
(IntPtr)address,
|
}
|
||||||
(IntPtr)size,
|
}
|
||||||
AllocationType.Release | AllocationType.CoalescePlaceholders));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RemoveProtection(address, size);
|
RemoveProtection(address, size);
|
||||||
@@ -130,7 +131,7 @@ namespace Ryujinx.Memory.WindowsShared
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
UnmapViewInternal(sharedMemory, location, size, owner);
|
UnmapViewInternal(sharedMemory, location, size, owner, updateProtection: false);
|
||||||
MapViewInternal(sharedMemory, srcOffset, location, size);
|
MapViewInternal(sharedMemory, srcOffset, location, size);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@@ -166,6 +167,8 @@ namespace Ryujinx.Memory.WindowsShared
|
|||||||
{
|
{
|
||||||
throw new WindowsApiException("MapViewOfFile3");
|
throw new WindowsApiException("MapViewOfFile3");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateProtection((ulong)location, (ulong)size, MemoryPermission.ReadAndWrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -178,18 +181,17 @@ namespace Ryujinx.Memory.WindowsShared
|
|||||||
{
|
{
|
||||||
ulong endAddress = address + size;
|
ulong endAddress = address + size;
|
||||||
|
|
||||||
var overlaps = Array.Empty<IntervalTreeNode<ulong, ulong>>();
|
var overlaps = new RangeNode<ulong>[InitialOverlapsSize];
|
||||||
|
|
||||||
lock (_mappings)
|
lock (_mappings)
|
||||||
{
|
{
|
||||||
int count = _mappings.Get(address, endAddress, ref overlaps);
|
int count = _mappings.GetNodes(address, endAddress, ref overlaps);
|
||||||
|
|
||||||
Debug.Assert(count == 1);
|
Debug.Assert(count == 1);
|
||||||
Debug.Assert(!IsMapped(overlaps[0].Value));
|
Debug.Assert(!IsMapped(overlaps[0].Value));
|
||||||
|
|
||||||
var overlap = overlaps[0];
|
var overlap = overlaps[0];
|
||||||
|
|
||||||
// Tree operations might modify the node start/end values, so save a copy before we modify the tree.
|
|
||||||
ulong overlapStart = overlap.Start;
|
ulong overlapStart = overlap.Start;
|
||||||
ulong overlapEnd = overlap.End;
|
ulong overlapEnd = overlap.End;
|
||||||
ulong overlapValue = overlap.Value;
|
ulong overlapValue = overlap.Value;
|
||||||
@@ -206,8 +208,8 @@ namespace Ryujinx.Memory.WindowsShared
|
|||||||
(IntPtr)size,
|
(IntPtr)size,
|
||||||
AllocationType.Release | AllocationType.PreservePlaceholder));
|
AllocationType.Release | AllocationType.PreservePlaceholder));
|
||||||
|
|
||||||
_mappings.Add(overlapStart, address, overlapValue);
|
_mappings.Add(new RangeNode<ulong>(overlapStart, address, overlapValue));
|
||||||
_mappings.Add(endAddress, overlapEnd, AddBackingOffset(overlapValue, endAddress - overlapStart));
|
_mappings.Add(new RangeNode<ulong>(endAddress, overlapEnd, AddBackingOffset(overlapValue, endAddress - overlapStart)));
|
||||||
}
|
}
|
||||||
else if (overlapStartsBefore)
|
else if (overlapStartsBefore)
|
||||||
{
|
{
|
||||||
@@ -218,7 +220,7 @@ namespace Ryujinx.Memory.WindowsShared
|
|||||||
(IntPtr)overlappedSize,
|
(IntPtr)overlappedSize,
|
||||||
AllocationType.Release | AllocationType.PreservePlaceholder));
|
AllocationType.Release | AllocationType.PreservePlaceholder));
|
||||||
|
|
||||||
_mappings.Add(overlapStart, address, overlapValue);
|
_mappings.Add(new RangeNode<ulong>(overlapStart, address, overlapValue));
|
||||||
}
|
}
|
||||||
else if (overlapEndsAfter)
|
else if (overlapEndsAfter)
|
||||||
{
|
{
|
||||||
@@ -229,10 +231,10 @@ namespace Ryujinx.Memory.WindowsShared
|
|||||||
(IntPtr)overlappedSize,
|
(IntPtr)overlappedSize,
|
||||||
AllocationType.Release | AllocationType.PreservePlaceholder));
|
AllocationType.Release | AllocationType.PreservePlaceholder));
|
||||||
|
|
||||||
_mappings.Add(endAddress, overlapEnd, AddBackingOffset(overlapValue, overlappedSize));
|
_mappings.Add(new RangeNode<ulong>(endAddress, overlapEnd, AddBackingOffset(overlapValue, overlappedSize)));
|
||||||
}
|
}
|
||||||
|
|
||||||
_mappings.Add(address, endAddress, backingOffset);
|
_mappings.Add(new RangeNode<ulong>(address, endAddress, backingOffset));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,7 +256,7 @@ namespace Ryujinx.Memory.WindowsShared
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
UnmapViewInternal(sharedMemory, location, size, owner);
|
UnmapViewInternal(sharedMemory, location, size, owner, updateProtection: true);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -273,19 +275,20 @@ namespace Ryujinx.Memory.WindowsShared
|
|||||||
/// <param name="location">Address to unmap</param>
|
/// <param name="location">Address to unmap</param>
|
||||||
/// <param name="size">Size of the region to unmap in bytes</param>
|
/// <param name="size">Size of the region to unmap in bytes</param>
|
||||||
/// <param name="owner">Memory block that owns the mapping</param>
|
/// <param name="owner">Memory block that owns the mapping</param>
|
||||||
|
/// <param name="updateProtection">Indicates if the memory protections should be updated after the unmap</param>
|
||||||
/// <exception cref="WindowsApiException">Thrown when the Windows API returns an error unmapping or remapping the memory</exception>
|
/// <exception cref="WindowsApiException">Thrown when the Windows API returns an error unmapping or remapping the memory</exception>
|
||||||
private void UnmapViewInternal(IntPtr sharedMemory, IntPtr location, IntPtr size, MemoryBlock owner)
|
private void UnmapViewInternal(IntPtr sharedMemory, IntPtr location, IntPtr size, MemoryBlock owner, bool updateProtection)
|
||||||
{
|
{
|
||||||
ulong startAddress = (ulong)location;
|
ulong startAddress = (ulong)location;
|
||||||
ulong unmapSize = (ulong)size;
|
ulong unmapSize = (ulong)size;
|
||||||
ulong endAddress = startAddress + unmapSize;
|
ulong endAddress = startAddress + unmapSize;
|
||||||
|
|
||||||
var overlaps = Array.Empty<IntervalTreeNode<ulong, ulong>>();
|
var overlaps = new RangeNode<ulong>[InitialOverlapsSize];
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
lock (_mappings)
|
lock (_mappings)
|
||||||
{
|
{
|
||||||
count = _mappings.Get(startAddress, endAddress, ref overlaps);
|
count = _mappings.GetNodes(startAddress, endAddress, ref overlaps);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int index = 0; index < count; index++)
|
for (int index = 0; index < count; index++)
|
||||||
@@ -294,19 +297,14 @@ namespace Ryujinx.Memory.WindowsShared
|
|||||||
|
|
||||||
if (IsMapped(overlap.Value))
|
if (IsMapped(overlap.Value))
|
||||||
{
|
{
|
||||||
// Tree operations might modify the node start/end values, so save a copy before we modify the tree.
|
|
||||||
ulong overlapStart = overlap.Start;
|
|
||||||
ulong overlapEnd = overlap.End;
|
|
||||||
ulong overlapValue = overlap.Value;
|
|
||||||
|
|
||||||
lock (_mappings)
|
lock (_mappings)
|
||||||
{
|
{
|
||||||
_mappings.Remove(overlap);
|
_mappings.Remove(overlap);
|
||||||
_mappings.Add(overlapStart, overlapEnd, ulong.MaxValue);
|
_mappings.Add(new RangeNode<ulong>(overlap.Start, overlap.End, ulong.MaxValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool overlapStartsBefore = overlapStart < startAddress;
|
bool overlapStartsBefore = overlap.Start < startAddress;
|
||||||
bool overlapEndsAfter = overlapEnd > endAddress;
|
bool overlapEndsAfter = overlap.End > endAddress;
|
||||||
|
|
||||||
if (overlapStartsBefore || overlapEndsAfter)
|
if (overlapStartsBefore || overlapEndsAfter)
|
||||||
{
|
{
|
||||||
@@ -323,25 +321,25 @@ namespace Ryujinx.Memory.WindowsShared
|
|||||||
{
|
{
|
||||||
partialUnmapState.PartialUnmapsCount++;
|
partialUnmapState.PartialUnmapsCount++;
|
||||||
|
|
||||||
if (!WindowsApi.UnmapViewOfFile2(WindowsApi.CurrentProcessHandle, (IntPtr)overlapStart, 2))
|
if (!WindowsApi.UnmapViewOfFile2(WindowsApi.CurrentProcessHandle, (IntPtr)overlap.Start, 2))
|
||||||
{
|
{
|
||||||
throw new WindowsApiException("UnmapViewOfFile2");
|
throw new WindowsApiException("UnmapViewOfFile2");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (overlapStartsBefore)
|
if (overlapStartsBefore)
|
||||||
{
|
{
|
||||||
ulong remapSize = startAddress - overlapStart;
|
ulong remapSize = startAddress - overlap.Start;
|
||||||
|
|
||||||
MapViewInternal(sharedMemory, overlapValue, (IntPtr)overlapStart, (IntPtr)remapSize);
|
MapViewInternal(sharedMemory, overlap.Value, (IntPtr)overlap.Start, (IntPtr)remapSize);
|
||||||
RestoreRangeProtection(overlapStart, remapSize);
|
RestoreRangeProtection(overlap.Start, remapSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (overlapEndsAfter)
|
if (overlapEndsAfter)
|
||||||
{
|
{
|
||||||
ulong overlappedSize = endAddress - overlapStart;
|
ulong overlappedSize = endAddress - overlap.Start;
|
||||||
ulong remapBackingOffset = overlapValue + overlappedSize;
|
ulong remapBackingOffset = overlap.Value + overlappedSize;
|
||||||
ulong remapAddress = overlapStart + overlappedSize;
|
ulong remapAddress = overlap.Start + overlappedSize;
|
||||||
ulong remapSize = overlapEnd - endAddress;
|
ulong remapSize = overlap.End - endAddress;
|
||||||
|
|
||||||
MapViewInternal(sharedMemory, remapBackingOffset, (IntPtr)remapAddress, (IntPtr)remapSize);
|
MapViewInternal(sharedMemory, remapBackingOffset, (IntPtr)remapAddress, (IntPtr)remapSize);
|
||||||
RestoreRangeProtection(remapAddress, remapSize);
|
RestoreRangeProtection(remapAddress, remapSize);
|
||||||
@@ -352,7 +350,7 @@ namespace Ryujinx.Memory.WindowsShared
|
|||||||
partialUnmapLock.DowngradeFromWriterLock();
|
partialUnmapLock.DowngradeFromWriterLock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!WindowsApi.UnmapViewOfFile2(WindowsApi.CurrentProcessHandle, (IntPtr)overlapStart, 2))
|
else if (!WindowsApi.UnmapViewOfFile2(WindowsApi.CurrentProcessHandle, (IntPtr)overlap.Start, 2))
|
||||||
{
|
{
|
||||||
throw new WindowsApiException("UnmapViewOfFile2");
|
throw new WindowsApiException("UnmapViewOfFile2");
|
||||||
}
|
}
|
||||||
@@ -360,7 +358,11 @@ namespace Ryujinx.Memory.WindowsShared
|
|||||||
}
|
}
|
||||||
|
|
||||||
CoalesceForUnmap(startAddress, unmapSize, owner);
|
CoalesceForUnmap(startAddress, unmapSize, owner);
|
||||||
RemoveProtection(startAddress, unmapSize);
|
|
||||||
|
if (updateProtection)
|
||||||
|
{
|
||||||
|
UpdateProtection(startAddress, unmapSize, MemoryPermission.None);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -374,44 +376,58 @@ namespace Ryujinx.Memory.WindowsShared
|
|||||||
ulong endAddress = address + size;
|
ulong endAddress = address + size;
|
||||||
ulong blockAddress = (ulong)owner.Pointer;
|
ulong blockAddress = (ulong)owner.Pointer;
|
||||||
ulong blockEnd = blockAddress + owner.Size;
|
ulong blockEnd = blockAddress + owner.Size;
|
||||||
var overlaps = Array.Empty<IntervalTreeNode<ulong, ulong>>();
|
|
||||||
int unmappedCount = 0;
|
int unmappedCount = 0;
|
||||||
|
|
||||||
lock (_mappings)
|
lock (_mappings)
|
||||||
{
|
{
|
||||||
int count = _mappings.Get(
|
RangeNode<ulong> node = _mappings.GetNodeByKey(address);
|
||||||
Math.Max(address - MinimumPageSize, blockAddress),
|
|
||||||
Math.Min(endAddress + MinimumPageSize, blockEnd), ref overlaps);
|
|
||||||
|
|
||||||
if (count < 2)
|
if (node == null)
|
||||||
{
|
{
|
||||||
// Nothing to coalesce if we only have 1 or no overlaps.
|
// Nothing to coalesce if we have no overlaps.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int index = 0; index < count; index++)
|
RangeNode<ulong> predecessor = node.Predecessor;
|
||||||
|
RangeNode<ulong> successor = null;
|
||||||
|
|
||||||
|
for (; node != null; node = successor)
|
||||||
{
|
{
|
||||||
var overlap = overlaps[index];
|
successor = node.Successor;
|
||||||
|
var overlap = node;
|
||||||
|
|
||||||
if (!IsMapped(overlap.Value))
|
if (!IsMapped(overlap.Value))
|
||||||
{
|
{
|
||||||
if (address > overlap.Start)
|
address = Math.Min(address, overlap.Start);
|
||||||
{
|
endAddress = Math.Max(endAddress, overlap.End);
|
||||||
address = overlap.Start;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (endAddress < overlap.End)
|
|
||||||
{
|
|
||||||
endAddress = overlap.End;
|
|
||||||
}
|
|
||||||
|
|
||||||
_mappings.Remove(overlap);
|
_mappings.Remove(overlap);
|
||||||
|
|
||||||
unmappedCount++;
|
unmappedCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (node.End >= endAddress)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_mappings.Add(address, endAddress, ulong.MaxValue);
|
if (predecessor != null && !IsMapped(predecessor.Value) && predecessor.Start >= blockAddress)
|
||||||
|
{
|
||||||
|
address = Math.Min(address, predecessor.Start);
|
||||||
|
|
||||||
|
_mappings.Remove(predecessor);
|
||||||
|
unmappedCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (successor != null && !IsMapped(successor.Value) && successor.End <= blockEnd)
|
||||||
|
{
|
||||||
|
endAddress = Math.Max(endAddress, successor.End);
|
||||||
|
|
||||||
|
_mappings.Remove(successor);
|
||||||
|
unmappedCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
_mappings.Add(new RangeNode<ulong>(address, endAddress, ulong.MaxValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unmappedCount > 1)
|
if (unmappedCount > 1)
|
||||||
@@ -462,60 +478,55 @@ namespace Ryujinx.Memory.WindowsShared
|
|||||||
ulong reprotectSize = (ulong)size;
|
ulong reprotectSize = (ulong)size;
|
||||||
ulong endAddress = reprotectAddress + reprotectSize;
|
ulong endAddress = reprotectAddress + reprotectSize;
|
||||||
|
|
||||||
var overlaps = Array.Empty<IntervalTreeNode<ulong, ulong>>();
|
bool success = true;
|
||||||
int count;
|
|
||||||
|
|
||||||
lock (_mappings)
|
lock (_mappings)
|
||||||
{
|
{
|
||||||
count = _mappings.Get(reprotectAddress, endAddress, ref overlaps);
|
RangeNode<ulong> node = _mappings.GetNodeByKey(reprotectAddress);
|
||||||
}
|
RangeNode<ulong> successorNode;
|
||||||
|
|
||||||
bool success = true;
|
for (; node != null; node = successorNode)
|
||||||
|
|
||||||
for (int index = 0; index < count; index++)
|
|
||||||
{
|
|
||||||
var overlap = overlaps[index];
|
|
||||||
|
|
||||||
ulong mappedAddress = overlap.Start;
|
|
||||||
ulong mappedSize = overlap.End - overlap.Start;
|
|
||||||
|
|
||||||
if (mappedAddress < reprotectAddress)
|
|
||||||
{
|
{
|
||||||
ulong delta = reprotectAddress - mappedAddress;
|
successorNode = node.Successor;
|
||||||
mappedAddress = reprotectAddress;
|
var overlap = node;
|
||||||
mappedSize -= delta;
|
|
||||||
}
|
|
||||||
|
|
||||||
ulong mappedEndAddress = mappedAddress + mappedSize;
|
ulong mappedAddress = overlap.Start;
|
||||||
|
ulong mappedSize = overlap.End - overlap.Start;
|
||||||
|
|
||||||
if (mappedEndAddress > endAddress)
|
if (mappedAddress < reprotectAddress)
|
||||||
{
|
|
||||||
ulong delta = mappedEndAddress - endAddress;
|
|
||||||
mappedSize -= delta;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!WindowsApi.VirtualProtect((IntPtr)mappedAddress, (IntPtr)mappedSize, WindowsApi.GetProtection(permission), out _))
|
|
||||||
{
|
|
||||||
if (throwOnError)
|
|
||||||
{
|
{
|
||||||
throw new WindowsApiException("VirtualProtect");
|
ulong delta = reprotectAddress - mappedAddress;
|
||||||
|
mappedAddress = reprotectAddress;
|
||||||
|
mappedSize -= delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
success = false;
|
ulong mappedEndAddress = mappedAddress + mappedSize;
|
||||||
}
|
|
||||||
|
|
||||||
// We only keep track of "non-standard" protections,
|
if (mappedEndAddress > endAddress)
|
||||||
// that is, everything that is not just RW (which is the default when views are mapped).
|
{
|
||||||
if (permission == MemoryPermission.ReadAndWrite)
|
ulong delta = mappedEndAddress - endAddress;
|
||||||
{
|
mappedSize -= delta;
|
||||||
RemoveProtection(mappedAddress, mappedSize);
|
}
|
||||||
}
|
|
||||||
else
|
if (!WindowsApi.VirtualProtect((IntPtr)mappedAddress, (IntPtr)mappedSize, WindowsApi.GetProtection(permission), out _))
|
||||||
{
|
{
|
||||||
AddProtection(mappedAddress, mappedSize, permission);
|
if (throwOnError)
|
||||||
|
{
|
||||||
|
throw new WindowsApiException("VirtualProtect");
|
||||||
|
}
|
||||||
|
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.End >= endAddress)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateProtection(reprotectAddress, reprotectSize, permission);
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -564,29 +575,30 @@ namespace Ryujinx.Memory.WindowsShared
|
|||||||
/// <param name="address">Address of the protected region</param>
|
/// <param name="address">Address of the protected region</param>
|
||||||
/// <param name="size">Size of the protected region in bytes</param>
|
/// <param name="size">Size of the protected region in bytes</param>
|
||||||
/// <param name="permission">Memory permissions of the region</param>
|
/// <param name="permission">Memory permissions of the region</param>
|
||||||
private void AddProtection(ulong address, ulong size, MemoryPermission permission)
|
private void UpdateProtection(ulong address, ulong size, MemoryPermission permission)
|
||||||
{
|
{
|
||||||
ulong endAddress = address + size;
|
ulong endAddress = address + size;
|
||||||
var overlaps = Array.Empty<IntervalTreeNode<ulong, MemoryPermission>>();
|
|
||||||
int count;
|
|
||||||
|
|
||||||
lock (_protections)
|
lock (_protections)
|
||||||
{
|
{
|
||||||
count = _protections.Get(address, endAddress, ref overlaps);
|
RangeNode<MemoryPermission> node = _protections.GetNodeByKey(address);
|
||||||
|
|
||||||
if (count == 1 &&
|
if (node != null &&
|
||||||
overlaps[0].Start <= address &&
|
node.Start <= address &&
|
||||||
overlaps[0].End >= endAddress &&
|
node.End >= endAddress &&
|
||||||
overlaps[0].Value == permission)
|
node.Value == permission)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RangeNode<MemoryPermission> successorNode;
|
||||||
|
|
||||||
ulong startAddress = address;
|
ulong startAddress = address;
|
||||||
|
|
||||||
for (int index = 0; index < count; index++)
|
for (; node != null; node = successorNode)
|
||||||
{
|
{
|
||||||
var protection = overlaps[index];
|
successorNode = node.Successor;
|
||||||
|
var protection = node;
|
||||||
|
|
||||||
ulong protAddress = protection.Start;
|
ulong protAddress = protection.Start;
|
||||||
ulong protEndAddress = protection.End;
|
ulong protEndAddress = protection.End;
|
||||||
@@ -610,17 +622,22 @@ namespace Ryujinx.Memory.WindowsShared
|
|||||||
{
|
{
|
||||||
if (startAddress > protAddress)
|
if (startAddress > protAddress)
|
||||||
{
|
{
|
||||||
_protections.Add(protAddress, startAddress, protPermission);
|
_protections.Add(new RangeNode<MemoryPermission>(protAddress, startAddress, protPermission));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (endAddress < protEndAddress)
|
if (endAddress < protEndAddress)
|
||||||
{
|
{
|
||||||
_protections.Add(endAddress, protEndAddress, protPermission);
|
_protections.Add(new RangeNode<MemoryPermission>(endAddress, protEndAddress, protPermission));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (node.End >= endAddress)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_protections.Add(startAddress, endAddress, permission);
|
_protections.Add(new RangeNode<MemoryPermission>(startAddress, endAddress, permission));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -632,16 +649,16 @@ namespace Ryujinx.Memory.WindowsShared
|
|||||||
private void RemoveProtection(ulong address, ulong size)
|
private void RemoveProtection(ulong address, ulong size)
|
||||||
{
|
{
|
||||||
ulong endAddress = address + size;
|
ulong endAddress = address + size;
|
||||||
var overlaps = Array.Empty<IntervalTreeNode<ulong, MemoryPermission>>();
|
|
||||||
int count;
|
|
||||||
|
|
||||||
lock (_protections)
|
lock (_protections)
|
||||||
{
|
{
|
||||||
count = _protections.Get(address, endAddress, ref overlaps);
|
RangeNode<MemoryPermission> node = _protections.GetNodeByKey(address);
|
||||||
|
RangeNode<MemoryPermission> successorNode;
|
||||||
|
|
||||||
for (int index = 0; index < count; index++)
|
for (; node != null; node = successorNode)
|
||||||
{
|
{
|
||||||
var protection = overlaps[index];
|
successorNode = node.Successor;
|
||||||
|
var protection = node;
|
||||||
|
|
||||||
ulong protAddress = protection.Start;
|
ulong protAddress = protection.Start;
|
||||||
ulong protEndAddress = protection.End;
|
ulong protEndAddress = protection.End;
|
||||||
@@ -651,12 +668,17 @@ namespace Ryujinx.Memory.WindowsShared
|
|||||||
|
|
||||||
if (address > protAddress)
|
if (address > protAddress)
|
||||||
{
|
{
|
||||||
_protections.Add(protAddress, address, protPermission);
|
_protections.Add(new RangeNode<MemoryPermission>(protAddress, address, protPermission));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (endAddress < protEndAddress)
|
if (endAddress < protEndAddress)
|
||||||
{
|
{
|
||||||
_protections.Add(endAddress, protEndAddress, protPermission);
|
_protections.Add(new RangeNode<MemoryPermission>(endAddress, protEndAddress, protPermission));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.End >= endAddress)
|
||||||
|
{
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -670,12 +692,12 @@ namespace Ryujinx.Memory.WindowsShared
|
|||||||
private void RestoreRangeProtection(ulong address, ulong size)
|
private void RestoreRangeProtection(ulong address, ulong size)
|
||||||
{
|
{
|
||||||
ulong endAddress = address + size;
|
ulong endAddress = address + size;
|
||||||
var overlaps = Array.Empty<IntervalTreeNode<ulong, MemoryPermission>>();
|
var overlaps = new RangeNode<MemoryPermission>[InitialOverlapsSize];
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
lock (_protections)
|
lock (_protections)
|
||||||
{
|
{
|
||||||
count = _protections.Get(address, endAddress, ref overlaps);
|
count = _protections.GetNodes(address, endAddress, ref overlaps);
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong startAddress = address;
|
ulong startAddress = address;
|
||||||
@@ -684,6 +706,12 @@ namespace Ryujinx.Memory.WindowsShared
|
|||||||
{
|
{
|
||||||
var protection = overlaps[index];
|
var protection = overlaps[index];
|
||||||
|
|
||||||
|
// If protection is R/W we don't need to reprotect as views are initially mapped as R/W.
|
||||||
|
if (protection.Value == MemoryPermission.ReadAndWrite)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
ulong protAddress = protection.Start;
|
ulong protAddress = protection.Start;
|
||||||
ulong protEndAddress = protection.End;
|
ulong protEndAddress = protection.End;
|
||||||
|
|
||||||
|
@@ -13,6 +13,16 @@ namespace Ryujinx.Tests.Cpu
|
|||||||
#if SimdCvt32
|
#if SimdCvt32
|
||||||
|
|
||||||
#region "ValueSource (Opcodes)"
|
#region "ValueSource (Opcodes)"
|
||||||
|
private static uint[] _Vrint_AMNP_V_F32_()
|
||||||
|
{
|
||||||
|
return new uint[]
|
||||||
|
{
|
||||||
|
0xf3ba0500u, // VRINTA.F32 Q0, Q0
|
||||||
|
0xf3ba0680u, // VRINTM.F32 Q0, Q0
|
||||||
|
0xf3ba0400u, // VRINTN.F32 Q0, Q0
|
||||||
|
0xf3ba0780u // VRINTP.F32 Q0, Q0
|
||||||
|
};
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "ValueSource (Types)"
|
#region "ValueSource (Types)"
|
||||||
@@ -64,6 +74,47 @@ namespace Ryujinx.Tests.Cpu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<ulong> _2S_F_()
|
||||||
|
{
|
||||||
|
yield return 0xFF7FFFFFFF7FFFFFul; // -Max Normal (float.MinValue)
|
||||||
|
yield return 0x8080000080800000ul; // -Min Normal
|
||||||
|
yield return 0x807FFFFF807FFFFFul; // -Max Subnormal
|
||||||
|
yield return 0x8000000180000001ul; // -Min Subnormal (-float.Epsilon)
|
||||||
|
yield return 0x7F7FFFFF7F7FFFFFul; // +Max Normal (float.MaxValue)
|
||||||
|
yield return 0x0080000000800000ul; // +Min Normal
|
||||||
|
yield return 0x007FFFFF007FFFFFul; // +Max Subnormal
|
||||||
|
yield return 0x0000000100000001ul; // +Min Subnormal (float.Epsilon)
|
||||||
|
|
||||||
|
if (!NoZeros)
|
||||||
|
{
|
||||||
|
yield return 0x8000000080000000ul; // -Zero
|
||||||
|
yield return 0x0000000000000000ul; // +Zero
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!NoInfs)
|
||||||
|
{
|
||||||
|
yield return 0xFF800000FF800000ul; // -Infinity
|
||||||
|
yield return 0x7F8000007F800000ul; // +Infinity
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!NoNaNs)
|
||||||
|
{
|
||||||
|
yield return 0xFFC00000FFC00000ul; // -QNaN (all zeros payload) (float.NaN)
|
||||||
|
yield return 0xFFBFFFFFFFBFFFFFul; // -SNaN (all ones payload)
|
||||||
|
yield return 0x7FC000007FC00000ul; // +QNaN (all zeros payload) (-float.NaN) (DefaultNaN)
|
||||||
|
yield return 0x7FBFFFFF7FBFFFFFul; // +SNaN (all ones payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int cnt = 1; cnt <= RndCnt; cnt++)
|
||||||
|
{
|
||||||
|
ulong rnd1 = GenNormalS();
|
||||||
|
ulong rnd2 = GenSubnormalS();
|
||||||
|
|
||||||
|
yield return (rnd1 << 32) | rnd1;
|
||||||
|
yield return (rnd2 << 32) | rnd2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static IEnumerable<ulong> _1D_F_()
|
private static IEnumerable<ulong> _1D_F_()
|
||||||
{
|
{
|
||||||
yield return 0xFFEFFFFFFFFFFFFFul; // -Max Normal (double.MinValue)
|
yield return 0xFFEFFFFFFFFFFFFFul; // -Max Normal (double.MinValue)
|
||||||
@@ -224,6 +275,35 @@ namespace Ryujinx.Tests.Cpu
|
|||||||
CompareAgainstUnicorn();
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test, Pairwise] [Explicit]
|
||||||
|
public void Vrint_AMNP_V_F32([ValueSource(nameof(_Vrint_AMNP_V_F32_))] uint opcode,
|
||||||
|
[Values(0u, 1u, 2u, 3u)] uint rd,
|
||||||
|
[Values(0u, 1u, 2u, 3u)] uint rm,
|
||||||
|
[ValueSource(nameof(_2S_F_))] ulong d0,
|
||||||
|
[ValueSource(nameof(_2S_F_))] ulong d1,
|
||||||
|
[ValueSource(nameof(_2S_F_))] ulong d2,
|
||||||
|
[ValueSource(nameof(_2S_F_))] ulong d3,
|
||||||
|
[Values] bool q)
|
||||||
|
{
|
||||||
|
if (q)
|
||||||
|
{
|
||||||
|
opcode |= 1 << 6;
|
||||||
|
|
||||||
|
rd >>= 1; rd <<= 1;
|
||||||
|
rm >>= 1; rm <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||||
|
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||||
|
|
||||||
|
V128 v0 = MakeVectorE0E1(d0, d1);
|
||||||
|
V128 v1 = MakeVectorE0E1(d2, d3);
|
||||||
|
|
||||||
|
SingleOpcode(opcode, v0: v0, v1: v1);
|
||||||
|
|
||||||
|
CompareAgainstUnicorn();
|
||||||
|
}
|
||||||
|
|
||||||
[Test, Pairwise, Description("VRINTX.F<size> <Sd>, <Sm>")]
|
[Test, Pairwise, Description("VRINTX.F<size> <Sd>, <Sm>")]
|
||||||
public void Vrintx_S([Values(0u, 1u)] uint rd,
|
public void Vrintx_S([Values(0u, 1u)] uint rd,
|
||||||
[Values(0u, 1u)] uint rm,
|
[Values(0u, 1u)] uint rm,
|
||||||
@@ -253,7 +333,7 @@ namespace Ryujinx.Tests.Cpu
|
|||||||
}
|
}
|
||||||
|
|
||||||
opcode |= ((size & 3) << 8);
|
opcode |= ((size & 3) << 8);
|
||||||
|
|
||||||
int fpscr = (int)rMode << (int)Fpcr.RMode;
|
int fpscr = (int)rMode << (int)Fpcr.RMode;
|
||||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2, fpscr: fpscr);
|
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2, fpscr: fpscr);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user