Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
f2087ca29e | |||
92d166ecb7 | |||
72e543e946 | |||
98c838b24c | |||
63c9c64196 | |||
a113ed0811 | |||
747876dc67 | |||
95cc18a7b4 | |||
c017c77365 | |||
98e05ee4b7 | |||
868919e101 | |||
9ca040c0ff |
@ -195,12 +195,13 @@ namespace ARMeilleure.Decoders
|
|||||||
ulong limitAddress)
|
ulong limitAddress)
|
||||||
{
|
{
|
||||||
ulong address = block.Address;
|
ulong address = block.Address;
|
||||||
|
int itBlockSize = 0;
|
||||||
|
|
||||||
OpCode opCode;
|
OpCode opCode;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (address >= limitAddress)
|
if (address >= limitAddress && itBlockSize == 0)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -210,6 +211,15 @@ namespace ARMeilleure.Decoders
|
|||||||
block.OpCodes.Add(opCode);
|
block.OpCodes.Add(opCode);
|
||||||
|
|
||||||
address += (ulong)opCode.OpCodeSizeInBytes;
|
address += (ulong)opCode.OpCodeSizeInBytes;
|
||||||
|
|
||||||
|
if (opCode is OpCodeT16IfThen it)
|
||||||
|
{
|
||||||
|
itBlockSize = it.IfThenBlockSize;
|
||||||
|
}
|
||||||
|
else if (itBlockSize > 0)
|
||||||
|
{
|
||||||
|
itBlockSize--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
while (!(IsBranch(opCode) || IsException(opCode)));
|
while (!(IsBranch(opCode) || IsException(opCode)));
|
||||||
|
|
||||||
@ -345,7 +355,14 @@ namespace ARMeilleure.Decoders
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return new OpCode(inst, address, opCode);
|
if (mode == ExecutionMode.Aarch32Thumb)
|
||||||
|
{
|
||||||
|
return new OpCodeT16(inst, address, opCode);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new OpCode(inst, address, opCode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
9
ARMeilleure/Decoders/IOpCode32Adr.cs
Normal file
9
ARMeilleure/Decoders/IOpCode32Adr.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
interface IOpCode32Adr
|
||||||
|
{
|
||||||
|
int Rd { get; }
|
||||||
|
|
||||||
|
int Immediate { get; }
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,8 @@
|
|||||||
namespace ARMeilleure.Decoders
|
namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
interface IOpCode32Alu : IOpCode32
|
interface IOpCode32Alu : IOpCode32, IOpCode32HasSetFlags
|
||||||
{
|
{
|
||||||
int Rd { get; }
|
int Rd { get; }
|
||||||
int Rn { get; }
|
int Rn { get; }
|
||||||
|
|
||||||
bool SetFlags { get; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
9
ARMeilleure/Decoders/IOpCode32AluImm.cs
Normal file
9
ARMeilleure/Decoders/IOpCode32AluImm.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
interface IOpCode32AluImm : IOpCode32Alu
|
||||||
|
{
|
||||||
|
int Immediate { get; }
|
||||||
|
|
||||||
|
bool IsRotated { get; }
|
||||||
|
}
|
||||||
|
}
|
10
ARMeilleure/Decoders/IOpCode32AluRsImm.cs
Normal file
10
ARMeilleure/Decoders/IOpCode32AluRsImm.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
interface IOpCode32AluRsImm : IOpCode32Alu
|
||||||
|
{
|
||||||
|
int Rm { get; }
|
||||||
|
int Immediate { get; }
|
||||||
|
|
||||||
|
ShiftType ShiftType { get; }
|
||||||
|
}
|
||||||
|
}
|
10
ARMeilleure/Decoders/IOpCode32AluRsReg.cs
Normal file
10
ARMeilleure/Decoders/IOpCode32AluRsReg.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
interface IOpCode32AluRsReg : IOpCode32Alu
|
||||||
|
{
|
||||||
|
int Rm { get; }
|
||||||
|
int Rs { get; }
|
||||||
|
|
||||||
|
ShiftType ShiftType { get; }
|
||||||
|
}
|
||||||
|
}
|
6
ARMeilleure/Decoders/IOpCode32Exception.cs
Normal file
6
ARMeilleure/Decoders/IOpCode32Exception.cs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
namespace ARMeilleure.Decoders;
|
||||||
|
|
||||||
|
interface IOpCode32Exception
|
||||||
|
{
|
||||||
|
int Id { get; }
|
||||||
|
}
|
7
ARMeilleure/Decoders/IOpCode32HasSetFlags.cs
Normal file
7
ARMeilleure/Decoders/IOpCode32HasSetFlags.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
interface IOpCode32HasSetFlags
|
||||||
|
{
|
||||||
|
bool? SetFlags { get; }
|
||||||
|
}
|
||||||
|
}
|
@ -7,5 +7,9 @@ namespace ARMeilleure.Decoders
|
|||||||
|
|
||||||
bool WBack { get; }
|
bool WBack { get; }
|
||||||
bool IsLoad { get; }
|
bool IsLoad { get; }
|
||||||
|
bool Index { get; }
|
||||||
|
bool Add { get; }
|
||||||
|
|
||||||
|
int Immediate { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -9,5 +9,7 @@ namespace ARMeilleure.Decoders
|
|||||||
int PostOffset { get; }
|
int PostOffset { get; }
|
||||||
|
|
||||||
bool IsLoad { get; }
|
bool IsLoad { get; }
|
||||||
|
|
||||||
|
int Offset { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
7
ARMeilleure/Decoders/IOpCode32MemReg.cs
Normal file
7
ARMeilleure/Decoders/IOpCode32MemReg.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
interface IOpCode32MemReg : IOpCode32Mem
|
||||||
|
{
|
||||||
|
int Rm { get; }
|
||||||
|
}
|
||||||
|
}
|
@ -18,10 +18,9 @@ namespace ARMeilleure.Decoders
|
|||||||
|
|
||||||
public OpCode(InstDescriptor inst, ulong address, int opCode)
|
public OpCode(InstDescriptor inst, ulong address, int opCode)
|
||||||
{
|
{
|
||||||
Address = address;
|
|
||||||
RawOpCode = opCode;
|
|
||||||
|
|
||||||
Instruction = inst;
|
Instruction = inst;
|
||||||
|
Address = address;
|
||||||
|
RawOpCode = opCode;
|
||||||
|
|
||||||
RegisterSize = RegisterSize.Int64;
|
RegisterSize = RegisterSize.Int64;
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ namespace ARMeilleure.Decoders
|
|||||||
public int Rd { get; }
|
public int Rd { get; }
|
||||||
public int Rn { get; }
|
public int Rn { get; }
|
||||||
|
|
||||||
public bool SetFlags { get; }
|
public bool? SetFlags { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32Alu(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32Alu(inst, address, opCode);
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ using ARMeilleure.Common;
|
|||||||
|
|
||||||
namespace ARMeilleure.Decoders
|
namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCode32AluImm : OpCode32Alu
|
class OpCode32AluImm : OpCode32Alu, IOpCode32AluImm
|
||||||
{
|
{
|
||||||
public int Immediate { get; }
|
public int Immediate { get; }
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
public bool NHigh { get; }
|
public bool NHigh { get; }
|
||||||
public bool MHigh { get; }
|
public bool MHigh { get; }
|
||||||
public bool R { get; }
|
public bool R { get; }
|
||||||
public bool SetFlags { get; }
|
public bool? SetFlags { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32AluMla(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32AluMla(inst, address, opCode);
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace ARMeilleure.Decoders
|
namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCode32AluRsImm : OpCode32Alu
|
class OpCode32AluRsImm : OpCode32Alu, IOpCode32AluRsImm
|
||||||
{
|
{
|
||||||
public int Rm { get; }
|
public int Rm { get; }
|
||||||
public int Immediate { get; }
|
public int Immediate { get; }
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace ARMeilleure.Decoders
|
namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCode32AluRsReg : OpCode32Alu
|
class OpCode32AluRsReg : OpCode32Alu, IOpCode32AluRsReg
|
||||||
{
|
{
|
||||||
public int Rm { get; }
|
public int Rm { get; }
|
||||||
public int Rs { get; }
|
public int Rs { get; }
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace ARMeilleure.Decoders
|
namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCode32AluUmull : OpCode32
|
class OpCode32AluUmull : OpCode32, IOpCode32HasSetFlags
|
||||||
{
|
{
|
||||||
public int RdLo { get; }
|
public int RdLo { get; }
|
||||||
public int RdHi { get; }
|
public int RdHi { get; }
|
||||||
@ -10,7 +10,7 @@
|
|||||||
public bool NHigh { get; }
|
public bool NHigh { get; }
|
||||||
public bool MHigh { get; }
|
public bool MHigh { get; }
|
||||||
|
|
||||||
public bool SetFlags { get; }
|
public bool? SetFlags { get; }
|
||||||
public DataOp DataOp { 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);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace ARMeilleure.Decoders
|
namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCode32Exception : OpCode32
|
class OpCode32Exception : OpCode32, IOpCode32Exception
|
||||||
{
|
{
|
||||||
public int Id { get; }
|
public int Id { get; }
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace ARMeilleure.Decoders
|
namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCode32MemReg : OpCode32Mem
|
class OpCode32MemReg : OpCode32Mem, IOpCode32MemReg
|
||||||
{
|
{
|
||||||
public int Rm { get; }
|
public int Rm { get; }
|
||||||
|
|
||||||
|
24
ARMeilleure/Decoders/OpCodeT16AddSubImm3.cs
Normal file
24
ARMeilleure/Decoders/OpCodeT16AddSubImm3.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16AddSubImm3: OpCodeT16, IOpCode32AluImm
|
||||||
|
{
|
||||||
|
public int Rd { get; }
|
||||||
|
public int Rn { get; }
|
||||||
|
|
||||||
|
public bool? SetFlags => null;
|
||||||
|
|
||||||
|
public int Immediate { get; }
|
||||||
|
|
||||||
|
public bool IsRotated { get; }
|
||||||
|
|
||||||
|
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AddSubImm3(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16AddSubImm3(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rd = (opCode >> 0) & 0x7;
|
||||||
|
Rn = (opCode >> 3) & 0x7;
|
||||||
|
Immediate = (opCode >> 6) & 0x7;
|
||||||
|
IsRotated = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
ARMeilleure/Decoders/OpCodeT16AddSubReg.cs
Normal file
20
ARMeilleure/Decoders/OpCodeT16AddSubReg.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16AddSubReg : OpCodeT16, IOpCode32AluReg
|
||||||
|
{
|
||||||
|
public int Rm { get; }
|
||||||
|
public int Rd { get; }
|
||||||
|
public int Rn { get; }
|
||||||
|
|
||||||
|
public bool? SetFlags => null;
|
||||||
|
|
||||||
|
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AddSubReg(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16AddSubReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rd = (opCode >> 0) & 0x7;
|
||||||
|
Rn = (opCode >> 3) & 0x7;
|
||||||
|
Rm = (opCode >> 6) & 0x7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
ARMeilleure/Decoders/OpCodeT16AddSubSp.cs
Normal file
23
ARMeilleure/Decoders/OpCodeT16AddSubSp.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
using ARMeilleure.State;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16AddSubSp : OpCodeT16, IOpCode32AluImm
|
||||||
|
{
|
||||||
|
public int Rd => RegisterAlias.Aarch32Sp;
|
||||||
|
public int Rn => RegisterAlias.Aarch32Sp;
|
||||||
|
|
||||||
|
public bool? SetFlags => false;
|
||||||
|
|
||||||
|
public int Immediate { get; }
|
||||||
|
|
||||||
|
public bool IsRotated => false;
|
||||||
|
|
||||||
|
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AddSubSp(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16AddSubSp(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Immediate = ((opCode >> 0) & 0x7f) << 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
ARMeilleure/Decoders/OpCodeT16Adr.cs
Normal file
20
ARMeilleure/Decoders/OpCodeT16Adr.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16Adr : OpCodeT16, IOpCode32Adr
|
||||||
|
{
|
||||||
|
public int Rd { get; }
|
||||||
|
|
||||||
|
public bool Add => true;
|
||||||
|
public int Immediate { get; }
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
Rd = (opCode >> 8) & 7;
|
||||||
|
|
||||||
|
int imm = (opCode & 0xff) << 2;
|
||||||
|
Immediate = (int)(GetPc() & 0xfffffffc) + imm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,22 +1,24 @@
|
|||||||
namespace ARMeilleure.Decoders
|
namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCodeT16AluImm8 : OpCodeT16, IOpCode32Alu
|
class OpCodeT16AluImm8 : OpCodeT16, IOpCode32AluImm
|
||||||
{
|
{
|
||||||
private int _rdn;
|
public int Rd { get; }
|
||||||
|
public int Rn { get; }
|
||||||
|
|
||||||
public int Rd => _rdn;
|
public bool? SetFlags => null;
|
||||||
public int Rn => _rdn;
|
|
||||||
|
|
||||||
public bool SetFlags => false;
|
|
||||||
|
|
||||||
public int Immediate { get; }
|
public int Immediate { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AluImm8(inst, address, opCode);
|
public bool IsRotated { get; }
|
||||||
|
|
||||||
|
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AluImm8(inst, address, opCode);
|
||||||
|
|
||||||
public OpCodeT16AluImm8(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCodeT16AluImm8(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
|
Rd = (opCode >> 8) & 0x7;
|
||||||
|
Rn = (opCode >> 8) & 0x7;
|
||||||
Immediate = (opCode >> 0) & 0xff;
|
Immediate = (opCode >> 0) & 0xff;
|
||||||
_rdn = (opCode >> 8) & 0x7;
|
IsRotated = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
24
ARMeilleure/Decoders/OpCodeT16AluImmZero.cs
Normal file
24
ARMeilleure/Decoders/OpCodeT16AluImmZero.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16AluImmZero : OpCodeT16, IOpCode32AluImm
|
||||||
|
{
|
||||||
|
public int Rd { get; }
|
||||||
|
public int Rn { get; }
|
||||||
|
|
||||||
|
public bool? SetFlags => null;
|
||||||
|
|
||||||
|
public int Immediate { get; }
|
||||||
|
|
||||||
|
public bool IsRotated { get; }
|
||||||
|
|
||||||
|
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AluImmZero(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16AluImmZero(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rd = (opCode >> 0) & 0x7;
|
||||||
|
Rn = (opCode >> 3) & 0x7;
|
||||||
|
Immediate = 0;
|
||||||
|
IsRotated = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
ARMeilleure/Decoders/OpCodeT16AluRegHigh.cs
Normal file
20
ARMeilleure/Decoders/OpCodeT16AluRegHigh.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16AluRegHigh : OpCodeT16, IOpCode32AluReg
|
||||||
|
{
|
||||||
|
public int Rm { get; }
|
||||||
|
public int Rd { get; }
|
||||||
|
public int Rn { get; }
|
||||||
|
|
||||||
|
public bool? SetFlags => false;
|
||||||
|
|
||||||
|
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AluRegHigh(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16AluRegHigh(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rd = ((opCode >> 0) & 0x7) | ((opCode >> 4) & 0x8);
|
||||||
|
Rn = ((opCode >> 0) & 0x7) | ((opCode >> 4) & 0x8);
|
||||||
|
Rm = (opCode >> 3) & 0xf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
ARMeilleure/Decoders/OpCodeT16AluRegLow.cs
Normal file
20
ARMeilleure/Decoders/OpCodeT16AluRegLow.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16AluRegLow : OpCodeT16, IOpCode32AluReg
|
||||||
|
{
|
||||||
|
public int Rm { get; }
|
||||||
|
public int Rd { get; }
|
||||||
|
public int Rn { get; }
|
||||||
|
|
||||||
|
public bool? SetFlags => null;
|
||||||
|
|
||||||
|
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AluRegLow(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16AluRegLow(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rd = (opCode >> 0) & 0x7;
|
||||||
|
Rn = (opCode >> 0) & 0x7;
|
||||||
|
Rm = (opCode >> 3) & 0x7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
ARMeilleure/Decoders/OpCodeT16AluUx.cs
Normal file
22
ARMeilleure/Decoders/OpCodeT16AluUx.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16AluUx : OpCodeT16, IOpCode32AluUx
|
||||||
|
{
|
||||||
|
public int Rm { get; }
|
||||||
|
public int Rd { get; }
|
||||||
|
public int Rn { get; }
|
||||||
|
|
||||||
|
public bool? SetFlags => false;
|
||||||
|
|
||||||
|
public int RotateBits => 0;
|
||||||
|
public bool Add => false;
|
||||||
|
|
||||||
|
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AluUx(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16AluUx(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rd = (opCode >> 0) & 0x7;
|
||||||
|
Rm = (opCode >> 3) & 0x7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
ARMeilleure/Decoders/OpCodeT16BImm11.cs
Normal file
15
ARMeilleure/Decoders/OpCodeT16BImm11.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16BImm11 : OpCode32, IOpCode32BImm
|
||||||
|
{
|
||||||
|
public long Immediate { get; }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16BImm11(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16BImm11(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
int imm = (opCode << 21) >> 20;
|
||||||
|
Immediate = GetPc() + imm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
ARMeilleure/Decoders/OpCodeT16BImm8.cs
Normal file
17
ARMeilleure/Decoders/OpCodeT16BImm8.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16BImm8 : OpCode32, IOpCode32BImm
|
||||||
|
{
|
||||||
|
public long Immediate { get; }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16BImm8(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16BImm8(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Cond = (Condition)((opCode >> 8) & 0xf);
|
||||||
|
|
||||||
|
int imm = (opCode << 24) >> 23;
|
||||||
|
Immediate = GetPc() + imm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
ARMeilleure/Decoders/OpCodeT16BImmCmp.cs
Normal file
19
ARMeilleure/Decoders/OpCodeT16BImmCmp.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16BImmCmp : OpCodeT16
|
||||||
|
{
|
||||||
|
public int Rn { get; }
|
||||||
|
|
||||||
|
public int Immediate { get; }
|
||||||
|
|
||||||
|
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16BImmCmp(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16BImmCmp(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rn = (opCode >> 0) & 0x7;
|
||||||
|
|
||||||
|
int imm = ((opCode >> 2) & 0x3e) | ((opCode >> 3) & 0x40);
|
||||||
|
Immediate = (int)GetPc() + imm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
namespace ARMeilleure.Decoders
|
namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCodeT16BReg : OpCodeT16, IOpCode32BReg
|
class OpCodeT16BReg : OpCodeT16, IOpCode32BReg
|
||||||
{
|
{
|
||||||
@ -11,4 +11,4 @@ namespace ARMeilleure.Decoders
|
|||||||
Rm = (opCode >> 3) & 0xf;
|
Rm = (opCode >> 3) & 0xf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
14
ARMeilleure/Decoders/OpCodeT16Exception.cs
Normal file
14
ARMeilleure/Decoders/OpCodeT16Exception.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16Exception : OpCodeT16, IOpCode32Exception
|
||||||
|
{
|
||||||
|
public int Id { get; }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16Exception(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16Exception(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Id = opCode & 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
34
ARMeilleure/Decoders/OpCodeT16IfThen.cs
Normal file
34
ARMeilleure/Decoders/OpCodeT16IfThen.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection.Emit;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16IfThen : OpCodeT16
|
||||||
|
{
|
||||||
|
public Condition[] IfThenBlockConds { get; }
|
||||||
|
|
||||||
|
public int IfThenBlockSize { get { return IfThenBlockConds.Length; } }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16IfThen(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16IfThen(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
List<Condition> conds = new();
|
||||||
|
|
||||||
|
int cond = (opCode >> 4) & 0xf;
|
||||||
|
int mask = opCode & 0xf;
|
||||||
|
|
||||||
|
conds.Add((Condition)cond);
|
||||||
|
|
||||||
|
while ((mask & 7) != 0)
|
||||||
|
{
|
||||||
|
int newLsb = (mask >> 3) & 1;
|
||||||
|
cond = (cond & 0xe) | newLsb;
|
||||||
|
mask <<= 1;
|
||||||
|
conds.Add((Condition)cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
IfThenBlockConds = conds.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
58
ARMeilleure/Decoders/OpCodeT16MemImm5.cs
Normal file
58
ARMeilleure/Decoders/OpCodeT16MemImm5.cs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
using ARMeilleure.Instructions;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16MemImm5 : OpCodeT16, IOpCode32Mem
|
||||||
|
{
|
||||||
|
public int Rt { get; }
|
||||||
|
public int Rn { get; }
|
||||||
|
|
||||||
|
public bool WBack => false;
|
||||||
|
public bool IsLoad { get; }
|
||||||
|
public bool Index => true;
|
||||||
|
public bool Add => true;
|
||||||
|
|
||||||
|
public int Immediate { get; }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16MemImm5(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16MemImm5(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rt = (opCode >> 0) & 7;
|
||||||
|
Rn = (opCode >> 3) & 7;
|
||||||
|
|
||||||
|
switch (inst.Name)
|
||||||
|
{
|
||||||
|
case InstName.Ldr:
|
||||||
|
case InstName.Ldrb:
|
||||||
|
case InstName.Ldrh:
|
||||||
|
IsLoad = true;
|
||||||
|
break;
|
||||||
|
case InstName.Str:
|
||||||
|
case InstName.Strb:
|
||||||
|
case InstName.Strh:
|
||||||
|
IsLoad = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (inst.Name)
|
||||||
|
{
|
||||||
|
case InstName.Str:
|
||||||
|
case InstName.Ldr:
|
||||||
|
Immediate = ((opCode >> 6) & 0x1f) << 2;
|
||||||
|
break;
|
||||||
|
case InstName.Strb:
|
||||||
|
case InstName.Ldrb:
|
||||||
|
Immediate = ((opCode >> 6) & 0x1f);
|
||||||
|
break;
|
||||||
|
case InstName.Strh:
|
||||||
|
case InstName.Ldrh:
|
||||||
|
Immediate = ((opCode >> 6) & 0x1f) << 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
ARMeilleure/Decoders/OpCodeT16MemLit.cs
Normal file
26
ARMeilleure/Decoders/OpCodeT16MemLit.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using ARMeilleure.State;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16MemLit : OpCodeT16, IOpCode32Mem
|
||||||
|
{
|
||||||
|
public int Rt { get; }
|
||||||
|
public int Rn => RegisterAlias.Aarch32Pc;
|
||||||
|
|
||||||
|
public bool WBack => false;
|
||||||
|
public bool IsLoad => true;
|
||||||
|
public bool Index => true;
|
||||||
|
public bool Add => true;
|
||||||
|
|
||||||
|
public int Immediate { get; }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16MemLit(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16MemLit(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rt = (opCode >> 8) & 7;
|
||||||
|
|
||||||
|
Immediate = (opCode & 0xff) << 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
34
ARMeilleure/Decoders/OpCodeT16MemMult.cs
Normal file
34
ARMeilleure/Decoders/OpCodeT16MemMult.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
using ARMeilleure.Instructions;
|
||||||
|
using System;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16MemMult : OpCodeT16, IOpCode32MemMult
|
||||||
|
{
|
||||||
|
public int Rn { get; }
|
||||||
|
public int RegisterMask { get; }
|
||||||
|
public int PostOffset { get; }
|
||||||
|
public bool IsLoad { get; }
|
||||||
|
public int Offset { get; }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16MemMult(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16MemMult(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
RegisterMask = opCode & 0xff;
|
||||||
|
Rn = (opCode >> 8) & 7;
|
||||||
|
|
||||||
|
int regCount = BitOperations.PopCount((uint)RegisterMask);
|
||||||
|
|
||||||
|
Offset = 0;
|
||||||
|
PostOffset = 4 * regCount;
|
||||||
|
IsLoad = inst.Name switch
|
||||||
|
{
|
||||||
|
InstName.Ldm => true,
|
||||||
|
InstName.Stm => false,
|
||||||
|
_ => throw new InvalidOperationException()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
27
ARMeilleure/Decoders/OpCodeT16MemReg.cs
Normal file
27
ARMeilleure/Decoders/OpCodeT16MemReg.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16MemReg : OpCodeT16, IOpCode32MemReg
|
||||||
|
{
|
||||||
|
public int Rm { get; }
|
||||||
|
public int Rt { get; }
|
||||||
|
public int Rn { get; }
|
||||||
|
|
||||||
|
public bool WBack => false;
|
||||||
|
public bool IsLoad { get; }
|
||||||
|
public bool Index => true;
|
||||||
|
public bool Add => true;
|
||||||
|
|
||||||
|
public int Immediate => throw new System.InvalidOperationException();
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16MemReg(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16MemReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rt = (opCode >> 0) & 7;
|
||||||
|
Rn = (opCode >> 3) & 7;
|
||||||
|
Rm = (opCode >> 6) & 7;
|
||||||
|
|
||||||
|
IsLoad = ((opCode >> 9) & 7) >= 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
28
ARMeilleure/Decoders/OpCodeT16MemSp.cs
Normal file
28
ARMeilleure/Decoders/OpCodeT16MemSp.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using ARMeilleure.State;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16MemSp : OpCodeT16, IOpCode32Mem
|
||||||
|
{
|
||||||
|
public int Rt { get; }
|
||||||
|
public int Rn => RegisterAlias.Aarch32Sp;
|
||||||
|
|
||||||
|
public bool WBack => false;
|
||||||
|
public bool IsLoad { get; }
|
||||||
|
public bool Index => true;
|
||||||
|
public bool Add => true;
|
||||||
|
|
||||||
|
public int Immediate { get; }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16MemSp(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16MemSp(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rt = (opCode >> 8) & 7;
|
||||||
|
|
||||||
|
IsLoad = ((opCode >> 11) & 1) != 0;
|
||||||
|
|
||||||
|
Immediate = ((opCode >> 0) & 0xff) << 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
42
ARMeilleure/Decoders/OpCodeT16MemStack.cs
Normal file
42
ARMeilleure/Decoders/OpCodeT16MemStack.cs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
using ARMeilleure.Instructions;
|
||||||
|
using ARMeilleure.State;
|
||||||
|
using System;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16MemStack : OpCodeT16, IOpCode32MemMult
|
||||||
|
{
|
||||||
|
public int Rn => RegisterAlias.Aarch32Sp;
|
||||||
|
public int RegisterMask { get; }
|
||||||
|
public int PostOffset { get; }
|
||||||
|
public bool IsLoad { get; }
|
||||||
|
public int Offset { get; }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16MemStack(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16MemStack(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
int extra = (opCode >> 8) & 1;
|
||||||
|
int regCount = BitOperations.PopCount((uint)opCode & 0x1ff);
|
||||||
|
|
||||||
|
switch (inst.Name)
|
||||||
|
{
|
||||||
|
case InstName.Push:
|
||||||
|
RegisterMask = (opCode & 0xff) | (extra << 14);
|
||||||
|
IsLoad = false;
|
||||||
|
Offset = -4 * regCount;
|
||||||
|
PostOffset = -4 * regCount;
|
||||||
|
break;
|
||||||
|
case InstName.Pop:
|
||||||
|
RegisterMask = (opCode & 0xff) | (extra << 15);
|
||||||
|
IsLoad = true;
|
||||||
|
Offset = 0;
|
||||||
|
PostOffset = 4 * regCount;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
ARMeilleure/Decoders/OpCodeT16ShiftImm.cs
Normal file
24
ARMeilleure/Decoders/OpCodeT16ShiftImm.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16ShiftImm : OpCodeT16, IOpCode32AluRsImm
|
||||||
|
{
|
||||||
|
public int Rd { get; }
|
||||||
|
public int Rn { get; }
|
||||||
|
public int Rm { get; }
|
||||||
|
|
||||||
|
public int Immediate { get; }
|
||||||
|
public ShiftType ShiftType { get; }
|
||||||
|
|
||||||
|
public bool? SetFlags => null;
|
||||||
|
|
||||||
|
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16ShiftImm(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16ShiftImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rd = (opCode >> 0) & 0x7;
|
||||||
|
Rm = (opCode >> 3) & 0x7;
|
||||||
|
Immediate = (opCode >> 6) & 0x1F;
|
||||||
|
ShiftType = (ShiftType)((opCode >> 11) & 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
27
ARMeilleure/Decoders/OpCodeT16ShiftReg.cs
Normal file
27
ARMeilleure/Decoders/OpCodeT16ShiftReg.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16ShiftReg : OpCodeT16, IOpCode32AluRsReg
|
||||||
|
{
|
||||||
|
public int Rm { get; }
|
||||||
|
public int Rs { get; }
|
||||||
|
public int Rd { get; }
|
||||||
|
|
||||||
|
public int Rn { get; }
|
||||||
|
|
||||||
|
public ShiftType ShiftType { get; }
|
||||||
|
|
||||||
|
public bool? SetFlags => null;
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16ShiftReg(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16ShiftReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rd = (opCode >> 0) & 7;
|
||||||
|
Rm = (opCode >> 0) & 7;
|
||||||
|
Rn = (opCode >> 3) & 7;
|
||||||
|
Rs = (opCode >> 3) & 7;
|
||||||
|
|
||||||
|
ShiftType = (ShiftType)(((opCode >> 6) & 1) | ((opCode >> 7) & 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
ARMeilleure/Decoders/OpCodeT16SpRel.cs
Normal file
24
ARMeilleure/Decoders/OpCodeT16SpRel.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using ARMeilleure.State;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16SpRel : OpCodeT16, IOpCode32AluImm
|
||||||
|
{
|
||||||
|
public int Rd { get; }
|
||||||
|
public int Rn => RegisterAlias.Aarch32Sp;
|
||||||
|
|
||||||
|
public bool? SetFlags => false;
|
||||||
|
|
||||||
|
public int Immediate { get; }
|
||||||
|
|
||||||
|
public bool IsRotated => false;
|
||||||
|
|
||||||
|
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16SpRel(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16SpRel(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rd = (opCode >> 8) & 0x7;
|
||||||
|
Immediate = ((opCode >> 0) & 0xff) << 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,4 @@
|
|||||||
using ARMeilleure.Instructions;
|
using ARMeilleure.Instructions;
|
||||||
using ARMeilleure.State;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
@ -29,9 +28,9 @@ namespace ARMeilleure.Decoders
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<InstInfo> AllInstA32 = new List<InstInfo>();
|
private static List<InstInfo> AllInstA32 = new();
|
||||||
private static List<InstInfo> AllInstT32 = new List<InstInfo>();
|
private static List<InstInfo> AllInstT32 = new();
|
||||||
private static List<InstInfo> AllInstA64 = new List<InstInfo>();
|
private static List<InstInfo> AllInstA64 = new();
|
||||||
|
|
||||||
private static InstInfo[][] InstA32FastLookup = new InstInfo[FastLookupSize][];
|
private static InstInfo[][] InstA32FastLookup = new InstInfo[FastLookupSize][];
|
||||||
private static InstInfo[][] InstT32FastLookup = new InstInfo[FastLookupSize][];
|
private static InstInfo[][] InstT32FastLookup = new InstInfo[FastLookupSize][];
|
||||||
@ -628,7 +627,7 @@ namespace ARMeilleure.Decoders
|
|||||||
SetA64("0>001110<<0xxxxx011110xxxxxxxxxx", InstName.Zip2_V, InstEmit.Zip2_V, OpCodeSimdReg.Create);
|
SetA64("0>001110<<0xxxxx011110xxxxxxxxxx", InstName.Zip2_V, InstEmit.Zip2_V, OpCodeSimdReg.Create);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "OpCode Table (AArch32)"
|
#region "OpCode Table (AArch32, A32)"
|
||||||
// Base
|
// Base
|
||||||
SetA32("<<<<0010101xxxxxxxxxxxxxxxxxxxxx", InstName.Adc, InstEmit32.Adc, OpCode32AluImm.Create);
|
SetA32("<<<<0010101xxxxxxxxxxxxxxxxxxxxx", InstName.Adc, InstEmit32.Adc, OpCode32AluImm.Create);
|
||||||
SetA32("<<<<0000101xxxxxxxxxxxxxxxx0xxxx", InstName.Adc, InstEmit32.Adc, OpCode32AluRsImm.Create);
|
SetA32("<<<<0000101xxxxxxxxxxxxxxxx0xxxx", InstName.Adc, InstEmit32.Adc, OpCode32AluRsImm.Create);
|
||||||
@ -649,7 +648,6 @@ namespace ARMeilleure.Decoders
|
|||||||
SetA32("1111101xxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Blx, InstEmit32.Blx, OpCode32BImm.Create);
|
SetA32("1111101xxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Blx, InstEmit32.Blx, OpCode32BImm.Create);
|
||||||
SetA32("<<<<000100101111111111110011xxxx", InstName.Blx, InstEmit32.Blxr, OpCode32BReg.Create);
|
SetA32("<<<<000100101111111111110011xxxx", InstName.Blx, InstEmit32.Blxr, OpCode32BReg.Create);
|
||||||
SetA32("<<<<000100101111111111110001xxxx", InstName.Bx, InstEmit32.Bx, OpCode32BReg.Create);
|
SetA32("<<<<000100101111111111110001xxxx", InstName.Bx, InstEmit32.Bx, OpCode32BReg.Create);
|
||||||
SetT32("xxxxxxxxxxxxxxxx010001110xxxx000", InstName.Bx, InstEmit32.Bx, OpCodeT16BReg.Create);
|
|
||||||
SetA32("11110101011111111111000000011111", InstName.Clrex, InstEmit32.Clrex, OpCode32.Create);
|
SetA32("11110101011111111111000000011111", InstName.Clrex, InstEmit32.Clrex, OpCode32.Create);
|
||||||
SetA32("<<<<000101101111xxxx11110001xxxx", InstName.Clz, InstEmit32.Clz, OpCode32AluReg.Create);
|
SetA32("<<<<000101101111xxxx11110001xxxx", InstName.Clz, InstEmit32.Clz, OpCode32AluReg.Create);
|
||||||
SetA32("<<<<00110111xxxx0000xxxxxxxxxxxx", InstName.Cmn, InstEmit32.Cmn, OpCode32AluImm.Create);
|
SetA32("<<<<00110111xxxx0000xxxxxxxxxxxx", InstName.Cmn, InstEmit32.Cmn, OpCode32AluImm.Create);
|
||||||
@ -702,7 +700,6 @@ namespace ARMeilleure.Decoders
|
|||||||
SetA32("<<<<0001101x0000xxxxxxxxxxx0xxxx", InstName.Mov, InstEmit32.Mov, OpCode32AluRsImm.Create);
|
SetA32("<<<<0001101x0000xxxxxxxxxxx0xxxx", InstName.Mov, InstEmit32.Mov, OpCode32AluRsImm.Create);
|
||||||
SetA32("<<<<0001101x0000xxxxxxxx0xx1xxxx", InstName.Mov, InstEmit32.Mov, OpCode32AluRsReg.Create);
|
SetA32("<<<<0001101x0000xxxxxxxx0xx1xxxx", InstName.Mov, InstEmit32.Mov, OpCode32AluRsReg.Create);
|
||||||
SetA32("<<<<00110000xxxxxxxxxxxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCode32AluImm16.Create);
|
SetA32("<<<<00110000xxxxxxxxxxxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCode32AluImm16.Create);
|
||||||
SetT32("xxxxxxxxxxxxxxxx00100xxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16AluImm8.Create);
|
|
||||||
SetA32("<<<<00110100xxxxxxxxxxxxxxxxxxxx", InstName.Movt, InstEmit32.Movt, OpCode32AluImm16.Create);
|
SetA32("<<<<00110100xxxxxxxxxxxxxxxxxxxx", InstName.Movt, InstEmit32.Movt, OpCode32AluImm16.Create);
|
||||||
SetA32("<<<<1110xxx1xxxxxxxx111xxxx1xxxx", InstName.Mrc, InstEmit32.Mrc, OpCode32System.Create);
|
SetA32("<<<<1110xxx1xxxxxxxx111xxxx1xxxx", InstName.Mrc, InstEmit32.Mrc, OpCode32System.Create);
|
||||||
SetA32("<<<<11000101xxxxxxxx111xxxxxxxxx", InstName.Mrrc, InstEmit32.Mrrc, OpCode32System.Create);
|
SetA32("<<<<11000101xxxxxxxx111xxxxxxxxx", InstName.Mrrc, InstEmit32.Mrrc, OpCode32System.Create);
|
||||||
@ -975,12 +972,85 @@ namespace ARMeilleure.Decoders
|
|||||||
SetA32("111100111x11<<10xxxx00011xx0xxxx", InstName.Vzip, InstEmit32.Vzip, OpCode32SimdCmpZ.Create);
|
SetA32("111100111x11<<10xxxx00011xx0xxxx", InstName.Vzip, InstEmit32.Vzip, OpCode32SimdCmpZ.Create);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
FillFastLookupTable(InstA32FastLookup, AllInstA32);
|
#region "OpCode Table (AArch32, T16/T32)"
|
||||||
FillFastLookupTable(InstT32FastLookup, AllInstT32);
|
// T16
|
||||||
FillFastLookupTable(InstA64FastLookup, AllInstA64);
|
SetT16("000<<xxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16ShiftImm.Create);
|
||||||
|
SetT16("0001100xxxxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT16AddSubReg.Create);
|
||||||
|
SetT16("0001101xxxxxxxxx", InstName.Sub, InstEmit32.Sub, OpCodeT16AddSubReg.Create);
|
||||||
|
SetT16("0001110xxxxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT16AddSubImm3.Create);
|
||||||
|
SetT16("0001111xxxxxxxxx", InstName.Sub, InstEmit32.Sub, OpCodeT16AddSubImm3.Create);
|
||||||
|
SetT16("00100xxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16AluImm8.Create);
|
||||||
|
SetT16("00101xxxxxxxxxxx", InstName.Cmp, InstEmit32.Cmp, OpCodeT16AluImm8.Create);
|
||||||
|
SetT16("00110xxxxxxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT16AluImm8.Create);
|
||||||
|
SetT16("00111xxxxxxxxxxx", InstName.Sub, InstEmit32.Sub, OpCodeT16AluImm8.Create);
|
||||||
|
SetT16("0100000000xxxxxx", InstName.And, InstEmit32.And, OpCodeT16AluRegLow.Create);
|
||||||
|
SetT16("0100000001xxxxxx", InstName.Eor, InstEmit32.Eor, OpCodeT16AluRegLow.Create);
|
||||||
|
SetT16("0100000010xxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16ShiftReg.Create);
|
||||||
|
SetT16("0100000011xxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16ShiftReg.Create);
|
||||||
|
SetT16("0100000100xxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16ShiftReg.Create);
|
||||||
|
SetT16("0100000101xxxxxx", InstName.Adc, InstEmit32.Adc, OpCodeT16AluRegLow.Create);
|
||||||
|
SetT16("0100000110xxxxxx", InstName.Sbc, InstEmit32.Sbc, OpCodeT16AluRegLow.Create);
|
||||||
|
SetT16("0100000111xxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16ShiftReg.Create);
|
||||||
|
SetT16("0100001000xxxxxx", InstName.Tst, InstEmit32.Tst, OpCodeT16AluRegLow.Create);
|
||||||
|
SetT16("0100001001xxxxxx", InstName.Rsb, InstEmit32.Rsb, OpCodeT16AluImmZero.Create);
|
||||||
|
SetT16("0100001010xxxxxx", InstName.Cmp, InstEmit32.Cmp, OpCodeT16AluRegLow.Create);
|
||||||
|
SetT16("0100001011xxxxxx", InstName.Cmn, InstEmit32.Cmn, OpCodeT16AluRegLow.Create);
|
||||||
|
SetT16("0100001100xxxxxx", InstName.Orr, InstEmit32.Orr, OpCodeT16AluRegLow.Create);
|
||||||
|
SetT16("0100001101xxxxxx", InstName.Mul, InstEmit32.Mul, OpCodeT16AluRegLow.Create);
|
||||||
|
SetT16("0100001110xxxxxx", InstName.Bic, InstEmit32.Bic, OpCodeT16AluRegLow.Create);
|
||||||
|
SetT16("0100001111xxxxxx", InstName.Mvn, InstEmit32.Mvn, OpCodeT16AluRegLow.Create);
|
||||||
|
SetT16("01000100xxxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT16AluRegHigh.Create);
|
||||||
|
SetT16("01000101xxxxxxxx", InstName.Cmp, InstEmit32.Cmp, OpCodeT16AluRegHigh.Create);
|
||||||
|
SetT16("01000110xxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16AluRegHigh.Create);
|
||||||
|
SetT16("010001110xxxx000", InstName.Bx, InstEmit32.Bx, OpCodeT16BReg.Create);
|
||||||
|
SetT16("010001111xxxx000", InstName.Blx, InstEmit32.Blx, OpCodeT16BReg.Create);
|
||||||
|
SetT16("01001xxxxxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT16MemLit.Create);
|
||||||
|
SetT16("0101000xxxxxxxxx", InstName.Str, InstEmit32.Str, OpCodeT16MemReg.Create);
|
||||||
|
SetT16("0101001xxxxxxxxx", InstName.Strh, InstEmit32.Strh, OpCodeT16MemReg.Create);
|
||||||
|
SetT16("0101010xxxxxxxxx", InstName.Strb, InstEmit32.Strb, OpCodeT16MemReg.Create);
|
||||||
|
SetT16("0101011xxxxxxxxx", InstName.Ldrsb, InstEmit32.Ldrsb, OpCodeT16MemReg.Create);
|
||||||
|
SetT16("0101100xxxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT16MemReg.Create);
|
||||||
|
SetT16("0101101xxxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT16MemReg.Create);
|
||||||
|
SetT16("0101110xxxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT16MemReg.Create);
|
||||||
|
SetT16("0101111xxxxxxxxx", InstName.Ldrsh, InstEmit32.Ldrsh, OpCodeT16MemReg.Create);
|
||||||
|
SetT16("01100xxxxxxxxxxx", InstName.Str, InstEmit32.Str, OpCodeT16MemImm5.Create);
|
||||||
|
SetT16("01101xxxxxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT16MemImm5.Create);
|
||||||
|
SetT16("01110xxxxxxxxxxx", InstName.Strb, InstEmit32.Strb, OpCodeT16MemImm5.Create);
|
||||||
|
SetT16("01111xxxxxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT16MemImm5.Create);
|
||||||
|
SetT16("10000xxxxxxxxxxx", InstName.Strh, InstEmit32.Strh, OpCodeT16MemImm5.Create);
|
||||||
|
SetT16("10001xxxxxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT16MemImm5.Create);
|
||||||
|
SetT16("10010xxxxxxxxxxx", InstName.Str, InstEmit32.Str, OpCodeT16MemSp.Create);
|
||||||
|
SetT16("10011xxxxxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT16MemSp.Create);
|
||||||
|
SetT16("10100xxxxxxxxxxx", InstName.Adr, InstEmit32.Adr, OpCodeT16Adr.Create);
|
||||||
|
SetT16("10101xxxxxxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT16SpRel.Create);
|
||||||
|
SetT16("101100000xxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT16AddSubSp.Create);
|
||||||
|
SetT16("101100001xxxxxxx", InstName.Sub, InstEmit32.Sub, OpCodeT16AddSubSp.Create);
|
||||||
|
SetT16("1011001000xxxxxx", InstName.Sxth, InstEmit32.Sxth, OpCodeT16AluUx.Create);
|
||||||
|
SetT16("1011001001xxxxxx", InstName.Sxtb, InstEmit32.Sxtb, OpCodeT16AluUx.Create);
|
||||||
|
SetT16("1011001010xxxxxx", InstName.Uxth, InstEmit32.Uxth, OpCodeT16AluUx.Create);
|
||||||
|
SetT16("1011001011xxxxxx", InstName.Uxtb, InstEmit32.Uxtb, OpCodeT16AluUx.Create);
|
||||||
|
SetT16("101100x1xxxxxxxx", InstName.Cbz, InstEmit32.Cbz, OpCodeT16BImmCmp.Create);
|
||||||
|
SetT16("1011010xxxxxxxxx", InstName.Push, InstEmit32.Stm, OpCodeT16MemStack.Create);
|
||||||
|
SetT16("1011101000xxxxxx", InstName.Rev, InstEmit32.Rev, OpCodeT16AluRegLow.Create);
|
||||||
|
SetT16("1011101001xxxxxx", InstName.Rev16, InstEmit32.Rev16, OpCodeT16AluRegLow.Create);
|
||||||
|
SetT16("1011101011xxxxxx", InstName.Revsh, InstEmit32.Revsh, OpCodeT16AluRegLow.Create);
|
||||||
|
SetT16("101110x1xxxxxxxx", InstName.Cbnz, InstEmit32.Cbnz, OpCodeT16BImmCmp.Create);
|
||||||
|
SetT16("1011110xxxxxxxxx", InstName.Pop, InstEmit32.Ldm, OpCodeT16MemStack.Create);
|
||||||
|
SetT16("10111111xxxx0000", InstName.Nop, InstEmit32.Nop, OpCodeT16.Create);
|
||||||
|
SetT16("10111111xxxx>>>>", InstName.It, InstEmit32.It, OpCodeT16IfThen.Create);
|
||||||
|
SetT16("11000xxxxxxxxxxx", InstName.Stm, InstEmit32.Stm, OpCodeT16MemMult.Create);
|
||||||
|
SetT16("11001xxxxxxxxxxx", InstName.Ldm, InstEmit32.Ldm, OpCodeT16MemMult.Create);
|
||||||
|
SetT16("1101<<<xxxxxxxxx", InstName.B, InstEmit32.B, OpCodeT16BImm8.Create);
|
||||||
|
SetT16("11011111xxxxxxxx", InstName.Svc, InstEmit32.Svc, OpCodeT16Exception.Create);
|
||||||
|
SetT16("11100xxxxxxxxxxx", InstName.B, InstEmit32.B, OpCodeT16BImm11.Create);
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
FillFastLookupTable(InstA32FastLookup, AllInstA32, ToFastLookupIndexA);
|
||||||
|
FillFastLookupTable(InstT32FastLookup, AllInstT32, ToFastLookupIndexT);
|
||||||
|
FillFastLookupTable(InstA64FastLookup, AllInstA64, ToFastLookupIndexA);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void FillFastLookupTable(InstInfo[][] table, List<InstInfo> allInsts)
|
private static void FillFastLookupTable(InstInfo[][] table, List<InstInfo> allInsts, Func<int, int> ToFastLookupIndex)
|
||||||
{
|
{
|
||||||
List<InstInfo>[] temp = new List<InstInfo>[FastLookupSize];
|
List<InstInfo>[] temp = new List<InstInfo>[FastLookupSize];
|
||||||
|
|
||||||
@ -1011,20 +1081,27 @@ namespace ARMeilleure.Decoders
|
|||||||
|
|
||||||
private static void SetA32(string encoding, InstName name, InstEmitter emitter, MakeOp makeOp)
|
private static void SetA32(string encoding, InstName name, InstEmitter emitter, MakeOp makeOp)
|
||||||
{
|
{
|
||||||
Set(encoding, ExecutionMode.Aarch32Arm, new InstDescriptor(name, emitter), makeOp);
|
Set(encoding, AllInstA32, new InstDescriptor(name, emitter), makeOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SetT16(string encoding, InstName name, InstEmitter emitter, MakeOp makeOp)
|
||||||
|
{
|
||||||
|
encoding = "xxxxxxxxxxxxxxxx" + encoding;
|
||||||
|
Set(encoding, AllInstT32, new InstDescriptor(name, emitter), makeOp);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SetT32(string encoding, InstName name, InstEmitter emitter, MakeOp makeOp)
|
private static void SetT32(string encoding, InstName name, InstEmitter emitter, MakeOp makeOp)
|
||||||
{
|
{
|
||||||
Set(encoding, ExecutionMode.Aarch32Thumb, new InstDescriptor(name, emitter), makeOp);
|
encoding = encoding.Substring(16) + encoding.Substring(0, 16);
|
||||||
|
Set(encoding, AllInstT32, new InstDescriptor(name, emitter), makeOp);
|
||||||
}
|
}
|
||||||
|
|
||||||
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, ExecutionMode.Aarch64, new InstDescriptor(name, emitter), makeOp);
|
Set(encoding, AllInstA64, new InstDescriptor(name, emitter), makeOp);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Set(string encoding, ExecutionMode mode, InstDescriptor inst, MakeOp makeOp)
|
private static void Set(string encoding, List<InstInfo> list, InstDescriptor inst, MakeOp makeOp)
|
||||||
{
|
{
|
||||||
int bit = encoding.Length - 1;
|
int bit = encoding.Length - 1;
|
||||||
int value = 0;
|
int value = 0;
|
||||||
@ -1073,7 +1150,7 @@ namespace ARMeilleure.Decoders
|
|||||||
|
|
||||||
if (xBits == 0)
|
if (xBits == 0)
|
||||||
{
|
{
|
||||||
InsertInst(new InstInfo(xMask, value, inst, makeOp), mode);
|
list.Add(new InstInfo(xMask, value, inst, makeOp));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1089,34 +1166,24 @@ namespace ARMeilleure.Decoders
|
|||||||
|
|
||||||
if (mask != blacklisted)
|
if (mask != blacklisted)
|
||||||
{
|
{
|
||||||
InsertInst(new InstInfo(xMask, value | mask, inst, makeOp), mode);
|
list.Add(new InstInfo(xMask, value | mask, inst, makeOp));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void InsertInst(InstInfo info, ExecutionMode mode)
|
|
||||||
{
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case ExecutionMode.Aarch32Arm: AllInstA32.Add(info); break;
|
|
||||||
case ExecutionMode.Aarch32Thumb: AllInstT32.Add(info); break;
|
|
||||||
case ExecutionMode.Aarch64: AllInstA64.Add(info); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static (InstDescriptor inst, MakeOp makeOp) GetInstA32(int opCode)
|
public static (InstDescriptor inst, MakeOp makeOp) GetInstA32(int opCode)
|
||||||
{
|
{
|
||||||
return GetInstFromList(InstA32FastLookup[ToFastLookupIndex(opCode)], opCode);
|
return GetInstFromList(InstA32FastLookup[ToFastLookupIndexA(opCode)], opCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static (InstDescriptor inst, MakeOp makeOp) GetInstT32(int opCode)
|
public static (InstDescriptor inst, MakeOp makeOp) GetInstT32(int opCode)
|
||||||
{
|
{
|
||||||
return GetInstFromList(InstT32FastLookup[ToFastLookupIndex(opCode)], opCode);
|
return GetInstFromList(InstT32FastLookup[ToFastLookupIndexT(opCode)], opCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static (InstDescriptor inst, MakeOp makeOp) GetInstA64(int opCode)
|
public static (InstDescriptor inst, MakeOp makeOp) GetInstA64(int opCode)
|
||||||
{
|
{
|
||||||
return GetInstFromList(InstA64FastLookup[ToFastLookupIndex(opCode)], opCode);
|
return GetInstFromList(InstA64FastLookup[ToFastLookupIndexA(opCode)], opCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static (InstDescriptor inst, MakeOp makeOp) GetInstFromList(InstInfo[] insts, int opCode)
|
private static (InstDescriptor inst, MakeOp makeOp) GetInstFromList(InstInfo[] insts, int opCode)
|
||||||
@ -1132,9 +1199,14 @@ namespace ARMeilleure.Decoders
|
|||||||
return (new InstDescriptor(InstName.Und, InstEmit.Und), null);
|
return (new InstDescriptor(InstName.Und, InstEmit.Und), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int ToFastLookupIndex(int value)
|
private static int ToFastLookupIndexA(int value)
|
||||||
{
|
{
|
||||||
return ((value >> 10) & 0x00F) | ((value >> 18) & 0xFF0);
|
return ((value >> 10) & 0x00F) | ((value >> 18) & 0xFF0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int ToFastLookupIndexT(int value)
|
||||||
|
{
|
||||||
|
return (value >> 4) & 0xFFF;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
// https://www.intel.com/content/dam/doc/white-paper/advanced-encryption-standard-new-instructions-set-paper.pdf
|
// https://www.intel.com/content/dam/doc/white-paper/advanced-encryption-standard-new-instructions-set-paper.pdf
|
||||||
|
|
||||||
using ARMeilleure.State;
|
using ARMeilleure.State;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace ARMeilleure.Instructions
|
namespace ARMeilleure.Instructions
|
||||||
{
|
{
|
||||||
static class CryptoHelper
|
static class CryptoHelper
|
||||||
{
|
{
|
||||||
#region "LookUp Tables"
|
#region "LookUp Tables"
|
||||||
private static readonly byte[] _sBox = new byte[]
|
private static ReadOnlySpan<byte> _sBox => new byte[]
|
||||||
{
|
{
|
||||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||||
@ -27,7 +28,7 @@ namespace ARMeilleure.Instructions
|
|||||||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
|
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly byte[] _invSBox = new byte[]
|
private static ReadOnlySpan<byte> _invSBox => new byte[]
|
||||||
{
|
{
|
||||||
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
|
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
|
||||||
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
|
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
|
||||||
@ -47,7 +48,7 @@ namespace ARMeilleure.Instructions
|
|||||||
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
|
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly byte[] _gfMul02 = new byte[]
|
private static ReadOnlySpan<byte> _gfMul02 => new byte[]
|
||||||
{
|
{
|
||||||
0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
|
0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
|
||||||
0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,
|
0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,
|
||||||
@ -67,7 +68,7 @@ namespace ARMeilleure.Instructions
|
|||||||
0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5
|
0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly byte[] _gfMul03 = new byte[]
|
private static ReadOnlySpan<byte> _gfMul03 => new byte[]
|
||||||
{
|
{
|
||||||
0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11,
|
0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11,
|
||||||
0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21,
|
0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21,
|
||||||
@ -87,7 +88,7 @@ namespace ARMeilleure.Instructions
|
|||||||
0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a
|
0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly byte[] _gfMul09 = new byte[]
|
private static ReadOnlySpan<byte> _gfMul09 => new byte[]
|
||||||
{
|
{
|
||||||
0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77,
|
0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77,
|
||||||
0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7,
|
0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7,
|
||||||
@ -107,7 +108,7 @@ namespace ARMeilleure.Instructions
|
|||||||
0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46
|
0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly byte[] _gfMul0B = new byte[]
|
private static ReadOnlySpan<byte> _gfMul0B => new byte[]
|
||||||
{
|
{
|
||||||
0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69,
|
0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69,
|
||||||
0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9,
|
0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9,
|
||||||
@ -127,7 +128,7 @@ namespace ARMeilleure.Instructions
|
|||||||
0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3
|
0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly byte[] _gfMul0D = new byte[]
|
private static ReadOnlySpan<byte> _gfMul0D => new byte[]
|
||||||
{
|
{
|
||||||
0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b,
|
0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b,
|
||||||
0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b,
|
0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b,
|
||||||
@ -147,7 +148,7 @@ namespace ARMeilleure.Instructions
|
|||||||
0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97
|
0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly byte[] _gfMul0E = new byte[]
|
private static ReadOnlySpan<byte> _gfMul0E => new byte[]
|
||||||
{
|
{
|
||||||
0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a,
|
0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a,
|
||||||
0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba,
|
0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba,
|
||||||
@ -167,12 +168,12 @@ namespace ARMeilleure.Instructions
|
|||||||
0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d
|
0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly byte[] _srPerm = new byte[]
|
private static ReadOnlySpan<byte> _srPerm => new byte[]
|
||||||
{
|
{
|
||||||
0, 13, 10, 7, 4, 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3
|
0, 13, 10, 7, 4, 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly byte[] _isrPerm = new byte[]
|
private static ReadOnlySpan<byte> _isrPerm => new byte[]
|
||||||
{
|
{
|
||||||
0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11
|
0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11
|
||||||
};
|
};
|
||||||
|
@ -20,7 +20,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand res = context.Add(n, m);
|
Operand res = context.Add(n, m);
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, res);
|
EmitNZFlagsCheck(context, res);
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
res = context.Add(res, carry);
|
res = context.Add(res, carry);
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, res);
|
EmitNZFlagsCheck(context, res);
|
||||||
|
|
||||||
@ -64,7 +64,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand res = context.BitwiseAnd(n, m);
|
Operand res = context.BitwiseAnd(n, m);
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, res);
|
EmitNZFlagsCheck(context, res);
|
||||||
}
|
}
|
||||||
@ -110,7 +110,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand res = context.BitwiseAnd(n, context.BitwiseNot(m));
|
Operand res = context.BitwiseAnd(n, context.BitwiseNot(m));
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, res);
|
EmitNZFlagsCheck(context, res);
|
||||||
}
|
}
|
||||||
@ -161,7 +161,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand res = context.BitwiseExclusiveOr(n, m);
|
Operand res = context.BitwiseExclusiveOr(n, m);
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, res);
|
EmitNZFlagsCheck(context, res);
|
||||||
}
|
}
|
||||||
@ -175,7 +175,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand m = GetAluM(context);
|
Operand m = GetAluM(context);
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, m);
|
EmitNZFlagsCheck(context, m);
|
||||||
}
|
}
|
||||||
@ -204,7 +204,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand res = context.Multiply(n, m);
|
Operand res = context.Multiply(n, m);
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, res);
|
EmitNZFlagsCheck(context, res);
|
||||||
}
|
}
|
||||||
@ -219,7 +219,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand res = context.BitwiseNot(m);
|
Operand res = context.BitwiseNot(m);
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, res);
|
EmitNZFlagsCheck(context, res);
|
||||||
}
|
}
|
||||||
@ -236,7 +236,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand res = context.BitwiseOr(n, m);
|
Operand res = context.BitwiseOr(n, m);
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, res);
|
EmitNZFlagsCheck(context, res);
|
||||||
}
|
}
|
||||||
@ -315,7 +315,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
res = context.Subtract(res, borrow);
|
res = context.Subtract(res, borrow);
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, res);
|
EmitNZFlagsCheck(context, res);
|
||||||
|
|
||||||
@ -335,7 +335,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand res = context.Subtract(m, n);
|
Operand res = context.Subtract(m, n);
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, res);
|
EmitNZFlagsCheck(context, res);
|
||||||
|
|
||||||
@ -359,7 +359,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
res = context.Subtract(res, borrow);
|
res = context.Subtract(res, borrow);
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, res);
|
EmitNZFlagsCheck(context, res);
|
||||||
|
|
||||||
@ -420,7 +420,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand res = context.Subtract(n, m);
|
Operand res = context.Subtract(n, m);
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, res);
|
EmitNZFlagsCheck(context, res);
|
||||||
|
|
||||||
@ -836,7 +836,7 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
|
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
|
||||||
|
|
||||||
EmitGenericAluStoreA32(context, op.Rd, op.SetFlags, value);
|
EmitGenericAluStoreA32(context, op.Rd, ShouldSetFlags(context), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,18 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
static class InstEmitAluHelper
|
static class InstEmitAluHelper
|
||||||
{
|
{
|
||||||
|
public static bool ShouldSetFlags(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
IOpCode32HasSetFlags op = (IOpCode32HasSetFlags)context.CurrOp;
|
||||||
|
|
||||||
|
if (op.SetFlags == null)
|
||||||
|
{
|
||||||
|
return !context.IsInIfThenBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
return op.SetFlags.Value;
|
||||||
|
}
|
||||||
|
|
||||||
public static void EmitNZFlagsCheck(ArmEmitterContext context, Operand d)
|
public static void EmitNZFlagsCheck(ArmEmitterContext context, Operand d)
|
||||||
{
|
{
|
||||||
SetFlag(context, PState.NFlag, context.ICompareLess (d, Const(d.Type, 0)));
|
SetFlag(context, PState.NFlag, context.ICompareLess (d, Const(d.Type, 0)));
|
||||||
@ -183,9 +195,9 @@ namespace ARMeilleure.Instructions
|
|||||||
switch (context.CurrOp)
|
switch (context.CurrOp)
|
||||||
{
|
{
|
||||||
// ARM32.
|
// ARM32.
|
||||||
case OpCode32AluImm op:
|
case IOpCode32AluImm op:
|
||||||
{
|
{
|
||||||
if (op.SetFlags && op.IsRotated)
|
if (ShouldSetFlags(context) && op.IsRotated)
|
||||||
{
|
{
|
||||||
SetFlag(context, PState.CFlag, Const((uint)op.Immediate >> 31));
|
SetFlag(context, PState.CFlag, Const((uint)op.Immediate >> 31));
|
||||||
}
|
}
|
||||||
@ -195,10 +207,8 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
case OpCode32AluImm16 op: return Const(op.Immediate);
|
case OpCode32AluImm16 op: return Const(op.Immediate);
|
||||||
|
|
||||||
case OpCode32AluRsImm op: return GetMShiftedByImmediate(context, op, setCarry);
|
case IOpCode32AluRsImm op: return GetMShiftedByImmediate(context, op, setCarry);
|
||||||
case OpCode32AluRsReg op: return GetMShiftedByReg(context, op, setCarry);
|
case IOpCode32AluRsReg op: return GetMShiftedByReg(context, op, setCarry);
|
||||||
|
|
||||||
case OpCodeT16AluImm8 op: return Const(op.Immediate);
|
|
||||||
|
|
||||||
case IOpCode32AluReg op: return GetIntA32(context, op.Rm);
|
case IOpCode32AluReg op: return GetIntA32(context, op.Rm);
|
||||||
|
|
||||||
@ -249,7 +259,7 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ARM32 helpers.
|
// ARM32 helpers.
|
||||||
public static Operand GetMShiftedByImmediate(ArmEmitterContext context, OpCode32AluRsImm op, bool setCarry)
|
public static Operand GetMShiftedByImmediate(ArmEmitterContext context, IOpCode32AluRsImm op, bool setCarry)
|
||||||
{
|
{
|
||||||
Operand m = GetIntA32(context, op.Rm);
|
Operand m = GetIntA32(context, op.Rm);
|
||||||
|
|
||||||
@ -267,7 +277,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
if (shift != 0)
|
if (shift != 0)
|
||||||
{
|
{
|
||||||
setCarry &= op.SetFlags;
|
setCarry &= ShouldSetFlags(context);
|
||||||
|
|
||||||
switch (op.ShiftType)
|
switch (op.ShiftType)
|
||||||
{
|
{
|
||||||
@ -305,7 +315,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return shift;
|
return shift;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Operand GetMShiftedByReg(ArmEmitterContext context, OpCode32AluRsReg op, bool setCarry)
|
public static Operand GetMShiftedByReg(ArmEmitterContext context, IOpCode32AluRsReg op, bool setCarry)
|
||||||
{
|
{
|
||||||
Operand m = GetIntA32(context, op.Rm);
|
Operand m = GetIntA32(context, op.Rm);
|
||||||
Operand s = context.ZeroExtend8(OperandType.I32, GetIntA32(context, op.Rs));
|
Operand s = context.ZeroExtend8(OperandType.I32, GetIntA32(context, op.Rs));
|
||||||
@ -314,7 +324,7 @@ namespace ARMeilleure.Instructions
|
|||||||
Operand zeroResult = m;
|
Operand zeroResult = m;
|
||||||
Operand shiftResult = m;
|
Operand shiftResult = m;
|
||||||
|
|
||||||
setCarry &= op.SetFlags;
|
setCarry &= ShouldSetFlags(context);
|
||||||
|
|
||||||
switch (op.ShiftType)
|
switch (op.ShiftType)
|
||||||
{
|
{
|
||||||
|
@ -20,11 +20,11 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
private static void EmitExceptionCall(ArmEmitterContext context, string name)
|
private static void EmitExceptionCall(ArmEmitterContext context, string name)
|
||||||
{
|
{
|
||||||
OpCode32Exception op = (OpCode32Exception)context.CurrOp;
|
IOpCode32Exception op = (IOpCode32Exception)context.CurrOp;
|
||||||
|
|
||||||
context.StoreToContext();
|
context.StoreToContext();
|
||||||
|
|
||||||
context.Call(typeof(NativeInterface).GetMethod(name), Const(op.Address), Const(op.Id));
|
context.Call(typeof(NativeInterface).GetMethod(name), Const(((IOpCode)op).Address), Const(op.Id));
|
||||||
|
|
||||||
context.LoadFromContext();
|
context.LoadFromContext();
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ namespace ARMeilleure.Instructions
|
|||||||
bool isThumb = IsThumb(context.CurrOp);
|
bool isThumb = IsThumb(context.CurrOp);
|
||||||
|
|
||||||
uint currentPc = isThumb
|
uint currentPc = isThumb
|
||||||
? pc | 1
|
? (pc - 2) | 1
|
||||||
: pc - 4;
|
: pc - 4;
|
||||||
|
|
||||||
SetIntA32(context, GetBankedRegisterAlias(context.Mode, RegisterAlias.Aarch32Lr), Const(currentPc));
|
SetIntA32(context, GetBankedRegisterAlias(context.Mode, RegisterAlias.Aarch32Lr), Const(currentPc));
|
||||||
@ -80,5 +80,32 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
EmitBxWritePc(context, GetIntA32(context, op.Rm), op.Rm);
|
EmitBxWritePc(context, GetIntA32(context, op.Rm), op.Rm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Cbnz(ArmEmitterContext context) => EmitCb(context, onNotZero: true);
|
||||||
|
public static void Cbz(ArmEmitterContext context) => EmitCb(context, onNotZero: false);
|
||||||
|
|
||||||
|
private static void EmitCb(ArmEmitterContext context, bool onNotZero)
|
||||||
|
{
|
||||||
|
OpCodeT16BImmCmp op = (OpCodeT16BImmCmp)context.CurrOp;
|
||||||
|
|
||||||
|
Operand value = GetIntOrZR(context, op.Rn);
|
||||||
|
Operand lblTarget = context.GetLabel((ulong)op.Immediate);
|
||||||
|
|
||||||
|
if (onNotZero)
|
||||||
|
{
|
||||||
|
context.BranchIfTrue(lblTarget, value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.BranchIfFalse(lblTarget, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void It(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
OpCodeT16IfThen op = (OpCodeT16IfThen)context.CurrOp;
|
||||||
|
|
||||||
|
context.SetIfThenBlockState(op.IfThenBlockConds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -32,7 +32,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void Ldm(ArmEmitterContext context)
|
public static void Ldm(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCode32MemMult op = (OpCode32MemMult)context.CurrOp;
|
IOpCode32MemMult op = (IOpCode32MemMult)context.CurrOp;
|
||||||
|
|
||||||
Operand n = GetIntA32(context, op.Rn);
|
Operand n = GetIntA32(context, op.Rn);
|
||||||
|
|
||||||
@ -95,7 +95,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void Stm(ArmEmitterContext context)
|
public static void Stm(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCode32MemMult op = (OpCode32MemMult)context.CurrOp;
|
IOpCode32MemMult op = (IOpCode32MemMult)context.CurrOp;
|
||||||
|
|
||||||
Operand n = context.Copy(GetIntA32(context, op.Rn));
|
Operand n = context.Copy(GetIntA32(context, op.Rn));
|
||||||
|
|
||||||
@ -151,7 +151,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
private static void EmitLoadOrStore(ArmEmitterContext context, int size, AccessType accType)
|
private static void EmitLoadOrStore(ArmEmitterContext context, int size, AccessType accType)
|
||||||
{
|
{
|
||||||
OpCode32Mem op = (OpCode32Mem)context.CurrOp;
|
IOpCode32Mem op = (IOpCode32Mem)context.CurrOp;
|
||||||
|
|
||||||
Operand n = context.Copy(GetIntA32AlignedPC(context, op.Rn));
|
Operand n = context.Copy(GetIntA32AlignedPC(context, op.Rn));
|
||||||
Operand m = GetMemM(context, setCarry: false);
|
Operand m = GetMemM(context, setCarry: false);
|
||||||
@ -255,5 +255,11 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Adr(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
IOpCode32Adr op = (IOpCode32Adr)context.CurrOp;
|
||||||
|
SetIntA32(context, op.Rd, Const(op.Immediate));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -549,9 +549,9 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
case OpCode32MemRsImm op: return GetMShiftedByImmediate(context, op, setCarry);
|
case OpCode32MemRsImm op: return GetMShiftedByImmediate(context, op, setCarry);
|
||||||
|
|
||||||
case OpCode32MemReg op: return GetIntA32(context, op.Rm);
|
case IOpCode32MemReg op: return GetIntA32(context, op.Rm);
|
||||||
|
|
||||||
case OpCode32Mem op: return Const(op.Immediate);
|
case IOpCode32Mem op: return Const(op.Immediate);
|
||||||
|
|
||||||
case OpCode32SimdMemImm op: return Const(op.Immediate);
|
case OpCode32SimdMemImm op: return Const(op.Immediate);
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand res = context.Add(a, context.Multiply(n, m));
|
Operand res = context.Add(a, context.Multiply(n, m));
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, res);
|
EmitNZFlagsCheck(context, res);
|
||||||
}
|
}
|
||||||
@ -250,13 +250,13 @@ namespace ARMeilleure.Instructions
|
|||||||
Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32)));
|
Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32)));
|
||||||
Operand lo = context.ConvertI64ToI32(res);
|
Operand lo = context.ConvertI64ToI32(res);
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, res);
|
EmitNZFlagsCheck(context, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
EmitGenericAluStoreA32(context, op.RdHi, op.SetFlags, hi);
|
EmitGenericAluStoreA32(context, op.RdHi, ShouldSetFlags(context), hi);
|
||||||
EmitGenericAluStoreA32(context, op.RdLo, op.SetFlags, lo);
|
EmitGenericAluStoreA32(context, op.RdLo, ShouldSetFlags(context), lo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Smulw_(ArmEmitterContext context)
|
public static void Smulw_(ArmEmitterContext context)
|
||||||
@ -320,13 +320,13 @@ namespace ARMeilleure.Instructions
|
|||||||
Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32)));
|
Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32)));
|
||||||
Operand lo = context.ConvertI64ToI32(res);
|
Operand lo = context.ConvertI64ToI32(res);
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, res);
|
EmitNZFlagsCheck(context, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
EmitGenericAluStoreA32(context, op.RdHi, op.SetFlags, hi);
|
EmitGenericAluStoreA32(context, op.RdHi, ShouldSetFlags(context), hi);
|
||||||
EmitGenericAluStoreA32(context, op.RdLo, op.SetFlags, lo);
|
EmitGenericAluStoreA32(context, op.RdLo, ShouldSetFlags(context), lo);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitMlal(ArmEmitterContext context, bool signed)
|
private static void EmitMlal(ArmEmitterContext context, bool signed)
|
||||||
@ -356,13 +356,13 @@ namespace ARMeilleure.Instructions
|
|||||||
Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32)));
|
Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32)));
|
||||||
Operand lo = context.ConvertI64ToI32(res);
|
Operand lo = context.ConvertI64ToI32(res);
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, res);
|
EmitNZFlagsCheck(context, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
EmitGenericAluStoreA32(context, op.RdHi, op.SetFlags, hi);
|
EmitGenericAluStoreA32(context, op.RdHi, ShouldSetFlags(context), hi);
|
||||||
EmitGenericAluStoreA32(context, op.RdLo, op.SetFlags, lo);
|
EmitGenericAluStoreA32(context, op.RdLo, ShouldSetFlags(context), lo);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void UpdateQFlag(ArmEmitterContext context, Operand q)
|
private static void UpdateQFlag(ArmEmitterContext context, Operand q)
|
||||||
|
@ -12,7 +12,8 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
static partial class InstEmit
|
static partial class InstEmit
|
||||||
{
|
{
|
||||||
private const int DczSizeLog2 = 4;
|
private const int DczSizeLog2 = 4; // Log2 size in words
|
||||||
|
public const int DczSizeInBytes = 4 << DczSizeLog2;
|
||||||
|
|
||||||
public static void Hint(ArmEmitterContext context)
|
public static void Hint(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
@ -87,7 +88,7 @@ namespace ARMeilleure.Instructions
|
|||||||
// DC ZVA
|
// DC ZVA
|
||||||
Operand t = GetIntOrZR(context, op.Rt);
|
Operand t = GetIntOrZR(context, op.Rt);
|
||||||
|
|
||||||
for (long offset = 0; offset < (4 << DczSizeLog2); offset += 8)
|
for (long offset = 0; offset < DczSizeInBytes; offset += 8)
|
||||||
{
|
{
|
||||||
Operand address = context.Add(t, Const(offset));
|
Operand address = context.Add(t, Const(offset));
|
||||||
|
|
||||||
@ -98,7 +99,12 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
|
|
||||||
// No-op
|
// No-op
|
||||||
case 0b11_011_0111_1110_001: //DC CIVAC
|
case 0b11_011_0111_1110_001: // DC CIVAC
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0b11_011_0111_0101_001: // IC IVAU
|
||||||
|
Operand target = Register(op.Rt, RegisterType.Integer, OperandType.I64);
|
||||||
|
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.InvalidateCacheLine)), target);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,7 @@ namespace ARMeilleure.Instructions
|
|||||||
Extr,
|
Extr,
|
||||||
Hint,
|
Hint,
|
||||||
Isb,
|
Isb,
|
||||||
|
It,
|
||||||
Ldar,
|
Ldar,
|
||||||
Ldaxp,
|
Ldaxp,
|
||||||
Ldaxr,
|
Ldaxr,
|
||||||
@ -512,6 +513,8 @@ namespace ARMeilleure.Instructions
|
|||||||
Mvn,
|
Mvn,
|
||||||
Pkh,
|
Pkh,
|
||||||
Pld,
|
Pld,
|
||||||
|
Pop,
|
||||||
|
Push,
|
||||||
Rev,
|
Rev,
|
||||||
Revsh,
|
Revsh,
|
||||||
Rsb,
|
Rsb,
|
||||||
|
@ -242,6 +242,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return (ulong)function.FuncPtr.ToInt64();
|
return (ulong)function.FuncPtr.ToInt64();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void InvalidateCacheLine(ulong address)
|
||||||
|
{
|
||||||
|
Context.Translator.InvalidateJitCacheRegion(address, InstEmit.DczSizeInBytes);
|
||||||
|
}
|
||||||
|
|
||||||
public static bool CheckSynchronization()
|
public static bool CheckSynchronization()
|
||||||
{
|
{
|
||||||
Statistics.PauseTimer();
|
Statistics.PauseTimer();
|
||||||
|
@ -824,7 +824,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return (ulong)(size - 1);
|
return (ulong)(size - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly byte[] ClzNibbleTbl = { 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
|
private static ReadOnlySpan<byte> ClzNibbleTbl => new byte[] { 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||||
|
|
||||||
public static ulong CountLeadingZeros(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
|
public static ulong CountLeadingZeros(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
|
||||||
{
|
{
|
||||||
|
@ -54,6 +54,11 @@ namespace ARMeilleure.Translation
|
|||||||
public bool HighCq { get; }
|
public bool HighCq { get; }
|
||||||
public Aarch32Mode Mode { get; }
|
public Aarch32Mode Mode { get; }
|
||||||
|
|
||||||
|
private int _ifThenBlockStateIndex = 0;
|
||||||
|
private Condition[] _ifThenBlockState = { };
|
||||||
|
public bool IsInIfThenBlock => _ifThenBlockStateIndex < _ifThenBlockState.Length;
|
||||||
|
public Condition CurrentIfThenBlockCond => _ifThenBlockState[_ifThenBlockStateIndex];
|
||||||
|
|
||||||
public ArmEmitterContext(
|
public ArmEmitterContext(
|
||||||
IMemoryManager memory,
|
IMemoryManager memory,
|
||||||
EntryTable<uint> countTable,
|
EntryTable<uint> countTable,
|
||||||
@ -196,5 +201,19 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetIfThenBlockState(Condition[] state)
|
||||||
|
{
|
||||||
|
_ifThenBlockState = state;
|
||||||
|
_ifThenBlockStateIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AdvanceIfThenBlockState()
|
||||||
|
{
|
||||||
|
if (IsInIfThenBlock)
|
||||||
|
{
|
||||||
|
_ifThenBlockStateIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -114,6 +114,7 @@ namespace ARMeilleure.Translation
|
|||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpscr))); // A32 only.
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpscr))); // A32 only.
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpsr)));
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpsr)));
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)));
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)));
|
||||||
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.InvalidateCacheLine)));
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidr)));
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidr)));
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidr32))); // A32 only.
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidr32))); // A32 only.
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl0)));
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl0)));
|
||||||
|
756
ARMeilleure/Translation/IntervalTree.cs
Normal file
756
ARMeilleure/Translation/IntervalTree.cs
Normal file
@ -0,0 +1,756 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Translation
|
||||||
|
{
|
||||||
|
/// <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>
|
||||||
|
public class IntervalTree<K, V> where K : IComparable<K>
|
||||||
|
{
|
||||||
|
private const int ArrayGrowthSize = 32;
|
||||||
|
|
||||||
|
private const bool Black = true;
|
||||||
|
private const bool Red = false;
|
||||||
|
private IntervalTreeNode<K, V> _root = null;
|
||||||
|
private int _count = 0;
|
||||||
|
|
||||||
|
public int Count => _count;
|
||||||
|
|
||||||
|
public IntervalTree() { }
|
||||||
|
|
||||||
|
#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 K[] overlaps, int overlapCount = 0)
|
||||||
|
{
|
||||||
|
GetValues(_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>
|
||||||
|
/// <param name="updateFactoryCallback">Optional factory used to create a new value if <paramref name="start"/> is already on the tree</param>
|
||||||
|
/// <exception cref="ArgumentNullException"><paramref name="value"/> is null</exception>
|
||||||
|
/// <returns>True if the value was added, false if the start key was already in the dictionary</returns>
|
||||||
|
public bool AddOrUpdate(K start, K end, V value, Func<K, V, V> updateFactoryCallback)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
return BSTInsert(start, end, value, updateFactoryCallback, out IntervalTreeNode<K, V> node);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an existing or 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>
|
||||||
|
/// <returns><paramref name="value"/> if <paramref name="start"/> is not yet on the tree, or the existing value otherwise</returns>
|
||||||
|
public V GetOrAdd(K start, K end, V value)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
BSTInsert(start, end, value, null, out IntervalTreeNode<K, V> node);
|
||||||
|
return node.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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)
|
||||||
|
{
|
||||||
|
int removed = Delete(key);
|
||||||
|
|
||||||
|
_count -= removed;
|
||||||
|
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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 values 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 GetValues(IntervalTreeNode<K, V> node, K start, K end, ref K[] overlaps, ref int overlapCount)
|
||||||
|
{
|
||||||
|
if (node == null || start.CompareTo(node.Max) >= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetValues(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.Start;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetValues(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">Key to search for</param>
|
||||||
|
/// <returns>Number of deleted values</returns>
|
||||||
|
private int Delete(K key)
|
||||||
|
{
|
||||||
|
IntervalTreeNode<K, V> nodeToDelete = GetNode(key);
|
||||||
|
|
||||||
|
if (nodeToDelete == null)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
IntervalTreeNode<K, V> replacementNode;
|
||||||
|
|
||||||
|
if (LeftOf(nodeToDelete) == null || RightOf(nodeToDelete) == null)
|
||||||
|
{
|
||||||
|
replacementNode = nodeToDelete;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
replacementNode = PredecessorOf(nodeToDelete);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the node with the largest key where <paramref name="node"/> is considered the root node.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="node">Root Node</param>
|
||||||
|
/// <returns>Node with the maximum key in the tree of <paramref name="node"/></returns>
|
||||||
|
private static IntervalTreeNode<K, V> Maximum(IntervalTreeNode<K, V> node)
|
||||||
|
{
|
||||||
|
IntervalTreeNode<K, V> tmp = node;
|
||||||
|
while (tmp.Right != null)
|
||||||
|
{
|
||||||
|
tmp = tmp.Right;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds the node whose key is immediately less than <paramref name="node"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="node">Node to find the predecessor of</param>
|
||||||
|
/// <returns>Predecessor of <paramref name="node"/></returns>
|
||||||
|
private static IntervalTreeNode<K, V> PredecessorOf(IntervalTreeNode<K, V> node)
|
||||||
|
{
|
||||||
|
if (node.Left != null)
|
||||||
|
{
|
||||||
|
return Maximum(node.Left);
|
||||||
|
}
|
||||||
|
IntervalTreeNode<K, V> parent = node.Parent;
|
||||||
|
while (parent != null && node == parent.Left)
|
||||||
|
{
|
||||||
|
node = parent;
|
||||||
|
parent = parent.Parent;
|
||||||
|
}
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Private Methods (RBL)
|
||||||
|
|
||||||
|
private void RestoreBalanceAfterRemoval(IntervalTreeNode<K, V> balanceNode)
|
||||||
|
{
|
||||||
|
IntervalTreeNode<K, V> ptr = balanceNode;
|
||||||
|
|
||||||
|
while (ptr != _root && ColorOf(ptr) == Black)
|
||||||
|
{
|
||||||
|
if (ptr == LeftOf(ParentOf(ptr)))
|
||||||
|
{
|
||||||
|
IntervalTreeNode<K, V> sibling = RightOf(ParentOf(ptr));
|
||||||
|
|
||||||
|
if (ColorOf(sibling) == Red)
|
||||||
|
{
|
||||||
|
SetColor(sibling, Black);
|
||||||
|
SetColor(ParentOf(ptr), Red);
|
||||||
|
RotateLeft(ParentOf(ptr));
|
||||||
|
sibling = RightOf(ParentOf(ptr));
|
||||||
|
}
|
||||||
|
if (ColorOf(LeftOf(sibling)) == Black && ColorOf(RightOf(sibling)) == Black)
|
||||||
|
{
|
||||||
|
SetColor(sibling, Red);
|
||||||
|
ptr = ParentOf(ptr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ColorOf(RightOf(sibling)) == Black)
|
||||||
|
{
|
||||||
|
SetColor(LeftOf(sibling), Black);
|
||||||
|
SetColor(sibling, Red);
|
||||||
|
RotateRight(sibling);
|
||||||
|
sibling = RightOf(ParentOf(ptr));
|
||||||
|
}
|
||||||
|
SetColor(sibling, ColorOf(ParentOf(ptr)));
|
||||||
|
SetColor(ParentOf(ptr), Black);
|
||||||
|
SetColor(RightOf(sibling), Black);
|
||||||
|
RotateLeft(ParentOf(ptr));
|
||||||
|
ptr = _root;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IntervalTreeNode<K, V> sibling = LeftOf(ParentOf(ptr));
|
||||||
|
|
||||||
|
if (ColorOf(sibling) == Red)
|
||||||
|
{
|
||||||
|
SetColor(sibling, Black);
|
||||||
|
SetColor(ParentOf(ptr), Red);
|
||||||
|
RotateRight(ParentOf(ptr));
|
||||||
|
sibling = LeftOf(ParentOf(ptr));
|
||||||
|
}
|
||||||
|
if (ColorOf(RightOf(sibling)) == Black && ColorOf(LeftOf(sibling)) == Black)
|
||||||
|
{
|
||||||
|
SetColor(sibling, Red);
|
||||||
|
ptr = ParentOf(ptr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ColorOf(LeftOf(sibling)) == Black)
|
||||||
|
{
|
||||||
|
SetColor(RightOf(sibling), Black);
|
||||||
|
SetColor(sibling, Red);
|
||||||
|
RotateLeft(sibling);
|
||||||
|
sibling = LeftOf(ParentOf(ptr));
|
||||||
|
}
|
||||||
|
SetColor(sibling, ColorOf(ParentOf(ptr)));
|
||||||
|
SetColor(ParentOf(ptr), Black);
|
||||||
|
SetColor(LeftOf(sibling), Black);
|
||||||
|
RotateRight(ParentOf(ptr));
|
||||||
|
ptr = _root;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SetColor(ptr, Black);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RestoreBalanceAfterInsertion(IntervalTreeNode<K, V> balanceNode)
|
||||||
|
{
|
||||||
|
SetColor(balanceNode, Red);
|
||||||
|
while (balanceNode != null && balanceNode != _root && ColorOf(ParentOf(balanceNode)) == Red)
|
||||||
|
{
|
||||||
|
if (ParentOf(balanceNode) == LeftOf(ParentOf(ParentOf(balanceNode))))
|
||||||
|
{
|
||||||
|
IntervalTreeNode<K, V> sibling = RightOf(ParentOf(ParentOf(balanceNode)));
|
||||||
|
|
||||||
|
if (ColorOf(sibling) == Red)
|
||||||
|
{
|
||||||
|
SetColor(ParentOf(balanceNode), Black);
|
||||||
|
SetColor(sibling, Black);
|
||||||
|
SetColor(ParentOf(ParentOf(balanceNode)), Red);
|
||||||
|
balanceNode = ParentOf(ParentOf(balanceNode));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (balanceNode == RightOf(ParentOf(balanceNode)))
|
||||||
|
{
|
||||||
|
balanceNode = ParentOf(balanceNode);
|
||||||
|
RotateLeft(balanceNode);
|
||||||
|
}
|
||||||
|
SetColor(ParentOf(balanceNode), Black);
|
||||||
|
SetColor(ParentOf(ParentOf(balanceNode)), Red);
|
||||||
|
RotateRight(ParentOf(ParentOf(balanceNode)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IntervalTreeNode<K, V> sibling = LeftOf(ParentOf(ParentOf(balanceNode)));
|
||||||
|
|
||||||
|
if (ColorOf(sibling) == Red)
|
||||||
|
{
|
||||||
|
SetColor(ParentOf(balanceNode), Black);
|
||||||
|
SetColor(sibling, Black);
|
||||||
|
SetColor(ParentOf(ParentOf(balanceNode)), Red);
|
||||||
|
balanceNode = ParentOf(ParentOf(balanceNode));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (balanceNode == LeftOf(ParentOf(balanceNode)))
|
||||||
|
{
|
||||||
|
balanceNode = ParentOf(balanceNode);
|
||||||
|
RotateRight(balanceNode);
|
||||||
|
}
|
||||||
|
SetColor(ParentOf(balanceNode), Black);
|
||||||
|
SetColor(ParentOf(ParentOf(balanceNode)), Red);
|
||||||
|
RotateLeft(ParentOf(ParentOf(balanceNode)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SetColor(_root, Black);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RotateLeft(IntervalTreeNode<K, V> node)
|
||||||
|
{
|
||||||
|
if (node != null)
|
||||||
|
{
|
||||||
|
IntervalTreeNode<K, V> right = RightOf(node);
|
||||||
|
node.Right = LeftOf(right);
|
||||||
|
if (node.Right != null)
|
||||||
|
{
|
||||||
|
node.Right.Parent = node;
|
||||||
|
}
|
||||||
|
IntervalTreeNode<K, V> nodeParent = ParentOf(node);
|
||||||
|
right.Parent = nodeParent;
|
||||||
|
if (nodeParent == null)
|
||||||
|
{
|
||||||
|
_root = right;
|
||||||
|
}
|
||||||
|
else if (node == LeftOf(nodeParent))
|
||||||
|
{
|
||||||
|
nodeParent.Left = right;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nodeParent.Right = right;
|
||||||
|
}
|
||||||
|
right.Left = node;
|
||||||
|
node.Parent = right;
|
||||||
|
|
||||||
|
PropagateFull(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RotateRight(IntervalTreeNode<K, V> node)
|
||||||
|
{
|
||||||
|
if (node != null)
|
||||||
|
{
|
||||||
|
IntervalTreeNode<K, V> left = LeftOf(node);
|
||||||
|
node.Left = RightOf(left);
|
||||||
|
if (node.Left != null)
|
||||||
|
{
|
||||||
|
node.Left.Parent = node;
|
||||||
|
}
|
||||||
|
IntervalTreeNode<K, V> nodeParent = ParentOf(node);
|
||||||
|
left.Parent = nodeParent;
|
||||||
|
if (nodeParent == null)
|
||||||
|
{
|
||||||
|
_root = left;
|
||||||
|
}
|
||||||
|
else if (node == RightOf(nodeParent))
|
||||||
|
{
|
||||||
|
nodeParent.Right = left;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nodeParent.Left = left;
|
||||||
|
}
|
||||||
|
left.Right = node;
|
||||||
|
node.Parent = left;
|
||||||
|
|
||||||
|
PropagateFull(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Safety-Methods
|
||||||
|
|
||||||
|
// These methods save memory by allowing us to forego sentinel nil nodes, as well as serve as protection against NullReferenceExceptions.
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the color of <paramref name="node"/>, or Black if it is null.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="node">Node</param>
|
||||||
|
/// <returns>The boolean color of <paramref name="node"/>, or black if null</returns>
|
||||||
|
private static bool ColorOf(IntervalTreeNode<K, V> node)
|
||||||
|
{
|
||||||
|
return node == null || node.Color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the color of <paramref name="node"/> node to <paramref name="color"/>.
|
||||||
|
/// <br></br>
|
||||||
|
/// This method does nothing if <paramref name="node"/> is null.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="node">Node to set the color of</param>
|
||||||
|
/// <param name="color">Color (Boolean)</param>
|
||||||
|
private static void SetColor(IntervalTreeNode<K, V> node, bool color)
|
||||||
|
{
|
||||||
|
if (node != null)
|
||||||
|
{
|
||||||
|
node.Color = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This method returns the left node of <paramref name="node"/>, or null if <paramref name="node"/> is null.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="node">Node to retrieve the left child from</param>
|
||||||
|
/// <returns>Left child of <paramref name="node"/></returns>
|
||||||
|
private static IntervalTreeNode<K, V> LeftOf(IntervalTreeNode<K, V> node)
|
||||||
|
{
|
||||||
|
return node?.Left;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This method returns the right node of <paramref name="node"/>, or null if <paramref name="node"/> is null.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="node">Node to retrieve the right child from</param>
|
||||||
|
/// <returns>Right child of <paramref name="node"/></returns>
|
||||||
|
private static IntervalTreeNode<K, V> RightOf(IntervalTreeNode<K, V> node)
|
||||||
|
{
|
||||||
|
return node?.Right;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the parent node of <paramref name="node"/>, or null if <paramref name="node"/> is null.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="node">Node to retrieve the parent from</param>
|
||||||
|
/// <returns>Parent of <paramref name="node"/></returns>
|
||||||
|
private static IntervalTreeNode<K, V> ParentOf(IntervalTreeNode<K, V> node)
|
||||||
|
{
|
||||||
|
return node?.Parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public bool ContainsKey(K key)
|
||||||
|
{
|
||||||
|
return GetNode(key) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
_root = null;
|
||||||
|
_count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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>
|
||||||
|
internal class IntervalTreeNode<K, V>
|
||||||
|
{
|
||||||
|
internal bool Color = true;
|
||||||
|
internal IntervalTreeNode<K, V> Left = null;
|
||||||
|
internal IntervalTreeNode<K, V> Right = null;
|
||||||
|
internal IntervalTreeNode<K, V> Parent = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The start of the range.
|
||||||
|
/// </summary>
|
||||||
|
internal K Start;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The end of the range.
|
||||||
|
/// </summary>
|
||||||
|
internal K End;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum end value of this node and all its children.
|
||||||
|
/// </summary>
|
||||||
|
internal K Max;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Value stored on this node.
|
||||||
|
/// </summary>
|
||||||
|
internal V Value;
|
||||||
|
|
||||||
|
public IntervalTreeNode(K start, K end, V value, IntervalTreeNode<K, V> parent)
|
||||||
|
{
|
||||||
|
this.Start = start;
|
||||||
|
this.End = end;
|
||||||
|
this.Max = end;
|
||||||
|
this.Value = value;
|
||||||
|
this.Parent = parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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 = 3061; //! To be incremented manually for each change to the ARMeilleure project.
|
private const uint InternalVersion = 3138; //! 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";
|
||||||
@ -585,7 +585,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
translator.RegisterFunction(infoEntry.Address, func);
|
translator.RegisterFunction(infoEntry.Address, func);
|
||||||
|
|
||||||
bool isAddressUnique = translator.Functions.TryAdd(infoEntry.Address, func);
|
bool isAddressUnique = translator.Functions.TryAdd(infoEntry.Address, infoEntry.GuestSize, func);
|
||||||
|
|
||||||
Debug.Assert(isAddressUnique, $"The address 0x{infoEntry.Address:X16} is not unique.");
|
Debug.Assert(isAddressUnique, $"The address 0x{infoEntry.Address:X16} is not unique.");
|
||||||
}
|
}
|
||||||
@ -815,7 +815,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
TranslatedFunction func = translator.Translate(address, item.funcProfile.Mode, item.funcProfile.HighCq);
|
TranslatedFunction func = translator.Translate(address, item.funcProfile.Mode, item.funcProfile.HighCq);
|
||||||
|
|
||||||
bool isAddressUnique = translator.Functions.TryAdd(address, func);
|
bool isAddressUnique = translator.Functions.TryAdd(address, func.GuestSize, func);
|
||||||
|
|
||||||
Debug.Assert(isAddressUnique, $"The address 0x{address:X16} is not unique.");
|
Debug.Assert(isAddressUnique, $"The address 0x{address:X16} is not unique.");
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
return address >= StaticCodeStart && address < StaticCodeStart + StaticCodeSize;
|
return address >= StaticCodeStart && address < StaticCodeStart + StaticCodeSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static ConcurrentQueue<(ulong address, FuncProfile funcProfile)> GetProfiledFuncsToTranslate(ConcurrentDictionary<ulong, TranslatedFunction> funcs)
|
internal static ConcurrentQueue<(ulong address, FuncProfile funcProfile)> GetProfiledFuncsToTranslate(TranslatorCache<TranslatedFunction> funcs)
|
||||||
{
|
{
|
||||||
var profiledFuncsToTranslate = new ConcurrentQueue<(ulong address, FuncProfile funcProfile)>();
|
var profiledFuncsToTranslate = new ConcurrentQueue<(ulong address, FuncProfile funcProfile)>();
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ namespace ARMeilleure.Translation
|
|||||||
private readonly AutoResetEvent _backgroundTranslatorEvent;
|
private readonly AutoResetEvent _backgroundTranslatorEvent;
|
||||||
private readonly ReaderWriterLock _backgroundTranslatorLock;
|
private readonly ReaderWriterLock _backgroundTranslatorLock;
|
||||||
|
|
||||||
internal ConcurrentDictionary<ulong, TranslatedFunction> Functions { get; }
|
internal TranslatorCache<TranslatedFunction> Functions { get; }
|
||||||
internal AddressTable<ulong> FunctionTable { get; }
|
internal AddressTable<ulong> FunctionTable { get; }
|
||||||
internal EntryTable<uint> CountTable { get; }
|
internal EntryTable<uint> CountTable { get; }
|
||||||
internal TranslatorStubs Stubs { get; }
|
internal TranslatorStubs Stubs { get; }
|
||||||
@ -75,7 +75,7 @@ namespace ARMeilleure.Translation
|
|||||||
JitCache.Initialize(allocator);
|
JitCache.Initialize(allocator);
|
||||||
|
|
||||||
CountTable = new EntryTable<uint>();
|
CountTable = new EntryTable<uint>();
|
||||||
Functions = new ConcurrentDictionary<ulong, TranslatedFunction>();
|
Functions = new TranslatorCache<TranslatedFunction>();
|
||||||
FunctionTable = new AddressTable<ulong>(for64Bits ? Levels64Bit : Levels32Bit);
|
FunctionTable = new AddressTable<ulong>(for64Bits ? Levels64Bit : Levels32Bit);
|
||||||
Stubs = new TranslatorStubs(this);
|
Stubs = new TranslatorStubs(this);
|
||||||
|
|
||||||
@ -93,12 +93,12 @@ namespace ARMeilleure.Translation
|
|||||||
{
|
{
|
||||||
_backgroundTranslatorLock.AcquireReaderLock(Timeout.Infinite);
|
_backgroundTranslatorLock.AcquireReaderLock(Timeout.Infinite);
|
||||||
|
|
||||||
if (_backgroundStack.TryPop(out RejitRequest request) &&
|
if (_backgroundStack.TryPop(out RejitRequest request) &&
|
||||||
_backgroundSet.TryRemove(request.Address, out _))
|
_backgroundSet.TryRemove(request.Address, out _))
|
||||||
{
|
{
|
||||||
TranslatedFunction func = Translate(request.Address, request.Mode, highCq: true);
|
TranslatedFunction func = Translate(request.Address, request.Mode, highCq: true);
|
||||||
|
|
||||||
Functions.AddOrUpdate(request.Address, func, (key, oldFunc) =>
|
Functions.AddOrUpdate(request.Address, func.GuestSize, func, (key, oldFunc) =>
|
||||||
{
|
{
|
||||||
EnqueueForDeletion(key, oldFunc);
|
EnqueueForDeletion(key, oldFunc);
|
||||||
return func;
|
return func;
|
||||||
@ -196,7 +196,7 @@ namespace ARMeilleure.Translation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ulong ExecuteSingle(State.ExecutionContext context, ulong address)
|
private ulong ExecuteSingle(State.ExecutionContext context, ulong address)
|
||||||
{
|
{
|
||||||
TranslatedFunction func = GetOrTranslate(address, context.ExecutionMode);
|
TranslatedFunction func = GetOrTranslate(address, context.ExecutionMode);
|
||||||
|
|
||||||
@ -215,7 +215,7 @@ namespace ARMeilleure.Translation
|
|||||||
{
|
{
|
||||||
func = Translate(address, mode, highCq: false);
|
func = Translate(address, mode, highCq: false);
|
||||||
|
|
||||||
TranslatedFunction oldFunc = Functions.GetOrAdd(address, func);
|
TranslatedFunction oldFunc = Functions.GetOrAdd(address, func.GuestSize, func);
|
||||||
|
|
||||||
if (oldFunc != func)
|
if (oldFunc != func)
|
||||||
{
|
{
|
||||||
@ -380,6 +380,13 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
Operand lblPredicateSkip = default;
|
Operand lblPredicateSkip = default;
|
||||||
|
|
||||||
|
if (context.IsInIfThenBlock && context.CurrentIfThenBlockCond != Condition.Al)
|
||||||
|
{
|
||||||
|
lblPredicateSkip = Label();
|
||||||
|
|
||||||
|
InstEmitFlowHelper.EmitCondBranch(context, lblPredicateSkip, context.CurrentIfThenBlockCond.Invert());
|
||||||
|
}
|
||||||
|
|
||||||
if (opCode is OpCode32 op && op.Cond < Condition.Al)
|
if (opCode is OpCode32 op && op.Cond < Condition.Al)
|
||||||
{
|
{
|
||||||
lblPredicateSkip = Label();
|
lblPredicateSkip = Label();
|
||||||
@ -400,6 +407,11 @@ namespace ARMeilleure.Translation
|
|||||||
{
|
{
|
||||||
context.MarkLabel(lblPredicateSkip);
|
context.MarkLabel(lblPredicateSkip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (context.IsInIfThenBlock && opCode.Instruction.Name != InstName.It)
|
||||||
|
{
|
||||||
|
context.AdvanceIfThenBlockState();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -459,7 +471,24 @@ namespace ARMeilleure.Translation
|
|||||||
// If rejit is running, stop it as it may be trying to rejit a function on the invalidated region.
|
// If rejit is running, stop it as it may be trying to rejit a function on the invalidated region.
|
||||||
ClearRejitQueue(allowRequeue: true);
|
ClearRejitQueue(allowRequeue: true);
|
||||||
|
|
||||||
// TODO: Completely remove functions overlapping the specified range from the cache.
|
ulong[] overlapAddresses = Array.Empty<ulong>();
|
||||||
|
|
||||||
|
int overlapsCount = Functions.GetOverlaps(address, size, ref overlapAddresses);
|
||||||
|
|
||||||
|
for (int index = 0; index < overlapsCount; index++)
|
||||||
|
{
|
||||||
|
ulong overlapAddress = overlapAddresses[index];
|
||||||
|
|
||||||
|
if (Functions.TryGetValue(overlapAddress, out TranslatedFunction overlap))
|
||||||
|
{
|
||||||
|
Functions.Remove(overlapAddress);
|
||||||
|
Volatile.Write(ref FunctionTable.GetValue(overlapAddress), FunctionTable.Fill);
|
||||||
|
EnqueueForDeletion(overlapAddress, overlap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Remove overlapping functions from the JitCache aswell.
|
||||||
|
// This should be done safely, with a mechanism to ensure the function is not being executed.
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void EnqueueForRejit(ulong guestAddress, ExecutionMode mode)
|
internal void EnqueueForRejit(ulong guestAddress, ExecutionMode mode)
|
||||||
@ -481,7 +510,9 @@ namespace ARMeilleure.Translation
|
|||||||
// Ensure no attempt will be made to compile new functions due to rejit.
|
// Ensure no attempt will be made to compile new functions due to rejit.
|
||||||
ClearRejitQueue(allowRequeue: false);
|
ClearRejitQueue(allowRequeue: false);
|
||||||
|
|
||||||
foreach (var func in Functions.Values)
|
List<TranslatedFunction> functions = Functions.AsList();
|
||||||
|
|
||||||
|
foreach (var func in functions)
|
||||||
{
|
{
|
||||||
JitCache.Unmap(func.FuncPtr);
|
JitCache.Unmap(func.FuncPtr);
|
||||||
|
|
||||||
|
95
ARMeilleure/Translation/TranslatorCache.cs
Normal file
95
ARMeilleure/Translation/TranslatorCache.cs
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Translation
|
||||||
|
{
|
||||||
|
internal class TranslatorCache<T>
|
||||||
|
{
|
||||||
|
private readonly IntervalTree<ulong, T> _tree;
|
||||||
|
private readonly ReaderWriterLock _treeLock;
|
||||||
|
|
||||||
|
public int Count => _tree.Count;
|
||||||
|
|
||||||
|
public TranslatorCache()
|
||||||
|
{
|
||||||
|
_tree = new IntervalTree<ulong, T>();
|
||||||
|
_treeLock = new ReaderWriterLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryAdd(ulong address, ulong size, T value)
|
||||||
|
{
|
||||||
|
return AddOrUpdate(address, size, value, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool AddOrUpdate(ulong address, ulong size, T value, Func<ulong, T, T> updateFactoryCallback)
|
||||||
|
{
|
||||||
|
_treeLock.AcquireWriterLock(Timeout.Infinite);
|
||||||
|
bool result = _tree.AddOrUpdate(address, address + size, value, updateFactoryCallback);
|
||||||
|
_treeLock.ReleaseWriterLock();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T GetOrAdd(ulong address, ulong size, T value)
|
||||||
|
{
|
||||||
|
_treeLock.AcquireWriterLock(Timeout.Infinite);
|
||||||
|
value = _tree.GetOrAdd(address, address + size, value);
|
||||||
|
_treeLock.ReleaseWriterLock();
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Remove(ulong address)
|
||||||
|
{
|
||||||
|
_treeLock.AcquireWriterLock(Timeout.Infinite);
|
||||||
|
bool removed = _tree.Remove(address) != 0;
|
||||||
|
_treeLock.ReleaseWriterLock();
|
||||||
|
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
_treeLock.AcquireWriterLock(Timeout.Infinite);
|
||||||
|
_tree.Clear();
|
||||||
|
_treeLock.ReleaseWriterLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ContainsKey(ulong address)
|
||||||
|
{
|
||||||
|
_treeLock.AcquireReaderLock(Timeout.Infinite);
|
||||||
|
bool result = _tree.ContainsKey(address);
|
||||||
|
_treeLock.ReleaseReaderLock();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetValue(ulong address, out T value)
|
||||||
|
{
|
||||||
|
_treeLock.AcquireReaderLock(Timeout.Infinite);
|
||||||
|
bool result = _tree.TryGet(address, out value);
|
||||||
|
_treeLock.ReleaseReaderLock();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetOverlaps(ulong address, ulong size, ref ulong[] overlaps)
|
||||||
|
{
|
||||||
|
_treeLock.AcquireReaderLock(Timeout.Infinite);
|
||||||
|
int count = _tree.Get(address, address + size, ref overlaps);
|
||||||
|
_treeLock.ReleaseReaderLock();
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<T> AsList()
|
||||||
|
{
|
||||||
|
_treeLock.AcquireReaderLock(Timeout.Infinite);
|
||||||
|
List<T> list = _tree.AsList();
|
||||||
|
_treeLock.ReleaseReaderLock();
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -39,6 +39,7 @@ namespace Ryujinx.Common.Logging
|
|||||||
ServiceLm,
|
ServiceLm,
|
||||||
ServiceMii,
|
ServiceMii,
|
||||||
ServiceMm,
|
ServiceMm,
|
||||||
|
ServiceMnpp,
|
||||||
ServiceNfc,
|
ServiceNfc,
|
||||||
ServiceNfp,
|
ServiceNfp,
|
||||||
ServiceNgct,
|
ServiceNgct,
|
||||||
|
@ -9,6 +9,7 @@ namespace Ryujinx.Common.Logging
|
|||||||
Error,
|
Error,
|
||||||
Guest,
|
Guest,
|
||||||
AccessLog,
|
AccessLog,
|
||||||
Notice
|
Notice,
|
||||||
|
Trace
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,6 +90,7 @@ namespace Ryujinx.Common.Logging
|
|||||||
public static Log? Guest { get; private set; }
|
public static Log? Guest { get; private set; }
|
||||||
public static Log? AccessLog { get; private set; }
|
public static Log? AccessLog { get; private set; }
|
||||||
public static Log? Stub { get; private set; }
|
public static Log? Stub { get; private set; }
|
||||||
|
public static Log? Trace { get; private set; }
|
||||||
public static Log Notice { get; } // Always enabled
|
public static Log Notice { get; } // Always enabled
|
||||||
|
|
||||||
static Logger()
|
static Logger()
|
||||||
@ -117,6 +118,7 @@ namespace Ryujinx.Common.Logging
|
|||||||
Error = new Log(LogLevel.Error);
|
Error = new Log(LogLevel.Error);
|
||||||
Warning = new Log(LogLevel.Warning);
|
Warning = new Log(LogLevel.Warning);
|
||||||
Info = new Log(LogLevel.Info);
|
Info = new Log(LogLevel.Info);
|
||||||
|
Trace = new Log(LogLevel.Trace);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void RestartTime()
|
public static void RestartTime()
|
||||||
@ -172,7 +174,7 @@ namespace Ryujinx.Common.Logging
|
|||||||
|
|
||||||
public static IReadOnlyCollection<LogLevel> GetEnabledLevels()
|
public static IReadOnlyCollection<LogLevel> GetEnabledLevels()
|
||||||
{
|
{
|
||||||
var logs = new Log?[] { Debug, Info, Warning, Error, Guest, AccessLog, Stub };
|
var logs = new Log?[] { Debug, Info, Warning, Error, Guest, AccessLog, Stub, Trace };
|
||||||
List<LogLevel> levels = new List<LogLevel>(logs.Length);
|
List<LogLevel> levels = new List<LogLevel>(logs.Length);
|
||||||
foreach (var log in logs)
|
foreach (var log in logs)
|
||||||
{
|
{
|
||||||
@ -196,6 +198,7 @@ namespace Ryujinx.Common.Logging
|
|||||||
case LogLevel.Guest : Guest = enabled ? new Log(LogLevel.Guest) : new Log?(); break;
|
case LogLevel.Guest : Guest = enabled ? new Log(LogLevel.Guest) : new Log?(); break;
|
||||||
case LogLevel.AccessLog : AccessLog = enabled ? new Log(LogLevel.AccessLog): new Log?(); break;
|
case LogLevel.AccessLog : AccessLog = enabled ? new Log(LogLevel.AccessLog): new Log?(); break;
|
||||||
case LogLevel.Stub : Stub = enabled ? new Log(LogLevel.Stub) : new Log?(); break;
|
case LogLevel.Stub : Stub = enabled ? new Log(LogLevel.Stub) : new Log?(); break;
|
||||||
|
case LogLevel.Trace : Trace = enabled ? new Log(LogLevel.Trace) : new Log?(); break;
|
||||||
default: throw new ArgumentException("Unknown Log Level");
|
default: throw new ArgumentException("Unknown Log Level");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ namespace Ryujinx.Common.Logging
|
|||||||
LogLevel.Error => ConsoleColor.Red,
|
LogLevel.Error => ConsoleColor.Red,
|
||||||
LogLevel.Stub => ConsoleColor.DarkGray,
|
LogLevel.Stub => ConsoleColor.DarkGray,
|
||||||
LogLevel.Notice => ConsoleColor.Cyan,
|
LogLevel.Notice => ConsoleColor.Cyan,
|
||||||
|
LogLevel.Trace => ConsoleColor.DarkCyan,
|
||||||
_ => ConsoleColor.Gray,
|
_ => ConsoleColor.Gray,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
|
using System;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace Ryujinx.Common
|
namespace Ryujinx.Common
|
||||||
{
|
{
|
||||||
public static class BitUtils
|
public static class BitUtils
|
||||||
{
|
{
|
||||||
private static readonly byte[] ClzNibbleTbl = { 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
||||||
|
|
||||||
public static uint AlignUp(uint value, int size)
|
public static uint AlignUp(uint value, int size)
|
||||||
{
|
{
|
||||||
return (uint)AlignUp((int)value, size);
|
return (uint)AlignUp((int)value, size);
|
||||||
@ -74,60 +75,7 @@ namespace Ryujinx.Common
|
|||||||
|
|
||||||
public static int Pow2RoundDown(int value)
|
public static int Pow2RoundDown(int value)
|
||||||
{
|
{
|
||||||
return IsPowerOfTwo32(value) ? value : Pow2RoundUp(value) >> 1;
|
return BitOperations.IsPow2(value) ? value : Pow2RoundUp(value) >> 1;
|
||||||
}
|
|
||||||
|
|
||||||
public static bool IsPowerOfTwo32(int value)
|
|
||||||
{
|
|
||||||
return value != 0 && (value & (value - 1)) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool IsPowerOfTwo64(long value)
|
|
||||||
{
|
|
||||||
return value != 0 && (value & (value - 1)) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int CountLeadingZeros32(int value)
|
|
||||||
{
|
|
||||||
return (int)CountLeadingZeros((ulong)value, 32);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int CountLeadingZeros64(long value)
|
|
||||||
{
|
|
||||||
return (int)CountLeadingZeros((ulong)value, 64);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ulong CountLeadingZeros(ulong value, int size)
|
|
||||||
{
|
|
||||||
if (value == 0ul)
|
|
||||||
{
|
|
||||||
return (ulong)size;
|
|
||||||
}
|
|
||||||
|
|
||||||
int nibbleIdx = size;
|
|
||||||
int preCount, count = 0;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
nibbleIdx -= 4;
|
|
||||||
preCount = ClzNibbleTbl[(int)(value >> nibbleIdx) & 0b1111];
|
|
||||||
count += preCount;
|
|
||||||
}
|
|
||||||
while (preCount == 4);
|
|
||||||
|
|
||||||
return (ulong)count;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int CountTrailingZeros32(int value)
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
while (((value >> count) & 1) == 0)
|
|
||||||
{
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long ReverseBits64(long value)
|
public static long ReverseBits64(long value)
|
||||||
|
@ -43,7 +43,7 @@ namespace Ryujinx.Common
|
|||||||
Prime32_1
|
Prime32_1
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly byte[] Xxh3KSecret = new byte[]
|
private static ReadOnlySpan<byte> Xxh3KSecret => new byte[]
|
||||||
{
|
{
|
||||||
0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c,
|
0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c,
|
||||||
0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f,
|
0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f,
|
||||||
|
@ -28,5 +28,10 @@ namespace Ryujinx.Cpu
|
|||||||
{
|
{
|
||||||
_translator.Execute(context, address);
|
_translator.Execute(context, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void InvalidateCacheRegion(ulong address, ulong size)
|
||||||
|
{
|
||||||
|
_translator.InvalidateJitCacheRegion(address, size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Version of the codegen (to be changed when codegen or guest format change).
|
/// Version of the codegen (to be changed when codegen or guest format change).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const ulong ShaderCodeGenVersion = 3063;
|
private const ulong ShaderCodeGenVersion = 3132;
|
||||||
|
|
||||||
// Progress reporting helpers
|
// Progress reporting helpers
|
||||||
private volatile int _shaderCount;
|
private volatile int _shaderCount;
|
||||||
|
@ -118,7 +118,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.H264
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ZigZag LUTs from libavcodec.
|
// ZigZag LUTs from libavcodec.
|
||||||
private static readonly byte[] ZigZagDirect = new byte[]
|
private static ReadOnlySpan<byte> ZigZagDirect => new byte[]
|
||||||
{
|
{
|
||||||
0, 1, 8, 16, 9, 2, 3, 10,
|
0, 1, 8, 16, 9, 2, 3, 10,
|
||||||
17, 24, 32, 25, 18, 11, 4, 5,
|
17, 24, 32, 25, 18, 11, 4, 5,
|
||||||
@ -130,7 +130,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.H264
|
|||||||
53, 60, 61, 54, 47, 55, 62, 63
|
53, 60, 61, 54, 47, 55, 62, 63
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly byte[] ZigZagScan = new byte[]
|
private static ReadOnlySpan<byte> ZigZagScan => new byte[]
|
||||||
{
|
{
|
||||||
0 + 0 * 4, 1 + 0 * 4, 0 + 1 * 4, 0 + 2 * 4,
|
0 + 0 * 4, 1 + 0 * 4, 0 + 1 * 4, 0 + 2 * 4,
|
||||||
1 + 1 * 4, 2 + 0 * 4, 3 + 0 * 4, 2 + 1 * 4,
|
1 + 1 * 4, 2 + 0 * 4, 3 + 0 * 4, 2 + 1 * 4,
|
||||||
@ -140,7 +140,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.H264
|
|||||||
|
|
||||||
private static void WriteScalingList(ref H264BitStreamWriter writer, IArray<byte> list)
|
private static void WriteScalingList(ref H264BitStreamWriter writer, IArray<byte> list)
|
||||||
{
|
{
|
||||||
byte[] scan = list.Length == 16 ? ZigZagScan : ZigZagDirect;
|
ReadOnlySpan<byte> scan = list.Length == 16 ? ZigZagScan : ZigZagDirect;
|
||||||
|
|
||||||
int lastScale = 8;
|
int lastScale = 8;
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
|
|
||||||
public ISurface CreateSurface(int width, int height) => new Surface(width, height);
|
public ISurface CreateSurface(int width, int height) => new Surface(width, height);
|
||||||
|
|
||||||
private static readonly byte[] LiteralToFilter = new byte[]
|
private static ReadOnlySpan<byte> LiteralToFilter => new byte[]
|
||||||
{
|
{
|
||||||
Constants.EightTapSmooth,
|
Constants.EightTapSmooth,
|
||||||
Constants.EightTap,
|
Constants.EightTap,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using Ryujinx.Graphics.Nvdec.Vp9.Common;
|
using Ryujinx.Graphics.Nvdec.Vp9.Common;
|
||||||
using Ryujinx.Graphics.Nvdec.Vp9.Types;
|
using Ryujinx.Graphics.Nvdec.Vp9.Types;
|
||||||
|
using System;
|
||||||
using static Ryujinx.Graphics.Nvdec.Vp9.Dsp.IntraPred;
|
using static Ryujinx.Graphics.Nvdec.Vp9.Dsp.IntraPred;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Nvdec.Vp9
|
namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
@ -24,7 +25,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
private const int NeedAbove = 1 << 2;
|
private const int NeedAbove = 1 << 2;
|
||||||
private const int NeedAboveRight = 1 << 3;
|
private const int NeedAboveRight = 1 << 3;
|
||||||
|
|
||||||
private static readonly byte[] ExtendModes = new byte[]
|
private static ReadOnlySpan<byte> ExtendModes => new byte[]
|
||||||
{
|
{
|
||||||
NeedAbove | NeedLeft, // DC
|
NeedAbove | NeedLeft, // DC
|
||||||
NeedAbove, // V
|
NeedAbove, // V
|
||||||
|
@ -10,7 +10,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||||||
public short Row;
|
public short Row;
|
||||||
public short Col;
|
public short Col;
|
||||||
|
|
||||||
private static readonly byte[] LogInBase2 = new byte[]
|
private static ReadOnlySpan<byte> LogInBase2 => new byte[]
|
||||||
{
|
{
|
||||||
0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||||
4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||||
|
@ -369,7 +369,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
inst &= Instruction.Mask;
|
inst &= Instruction.Mask;
|
||||||
bool isImage = inst == Instruction.ImageLoad || inst == Instruction.ImageStore || inst == Instruction.ImageAtomic;
|
bool isImage = inst == Instruction.ImageLoad || inst == Instruction.ImageStore || inst == Instruction.ImageAtomic;
|
||||||
bool isWrite = inst == Instruction.ImageStore || inst == Instruction.ImageAtomic;
|
bool isWrite = inst == Instruction.ImageStore || inst == Instruction.ImageAtomic;
|
||||||
bool accurateType = inst != Instruction.Lod;
|
bool accurateType = inst != Instruction.Lod && inst != Instruction.TextureSize;
|
||||||
bool coherent = flags.HasFlag(TextureFlags.Coherent);
|
bool coherent = flags.HasFlag(TextureFlags.Coherent);
|
||||||
|
|
||||||
if (isImage)
|
if (isImage)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
|
using System.Numerics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
using static Ryujinx.Graphics.Texture.BlockLinearConstants;
|
using static Ryujinx.Graphics.Texture.BlockLinearConstants;
|
||||||
@ -47,15 +48,15 @@ namespace Ryujinx.Graphics.Texture
|
|||||||
{
|
{
|
||||||
_texBpp = bpp;
|
_texBpp = bpp;
|
||||||
|
|
||||||
_bppShift = BitUtils.CountTrailingZeros32(bpp);
|
_bppShift = BitOperations.TrailingZeroCount(bpp);
|
||||||
|
|
||||||
_bhMask = gobBlocksInY - 1;
|
_bhMask = gobBlocksInY - 1;
|
||||||
_bdMask = gobBlocksInZ - 1;
|
_bdMask = gobBlocksInZ - 1;
|
||||||
|
|
||||||
_bhShift = BitUtils.CountTrailingZeros32(gobBlocksInY);
|
_bhShift = BitOperations.TrailingZeroCount(gobBlocksInY);
|
||||||
_bdShift = BitUtils.CountTrailingZeros32(gobBlocksInZ);
|
_bdShift = BitOperations.TrailingZeroCount(gobBlocksInZ);
|
||||||
|
|
||||||
_xShift = BitUtils.CountTrailingZeros32(GobSize * gobBlocksInY * gobBlocksInZ);
|
_xShift = BitOperations.TrailingZeroCount(GobSize * gobBlocksInY * gobBlocksInZ);
|
||||||
|
|
||||||
RobAndSliceSizes rsSizes = GetRobAndSliceSizes(width, height, gobBlocksInY, gobBlocksInZ);
|
RobAndSliceSizes rsSizes = GetRobAndSliceSizes(width, height, gobBlocksInY, gobBlocksInZ);
|
||||||
|
|
||||||
|
@ -36,6 +36,11 @@ namespace Ryujinx.HLE.HOS
|
|||||||
_cpuContext.Execute(context, codeAddress);
|
_cpuContext.Execute(context, codeAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void InvalidateCacheRegion(ulong address, ulong size)
|
||||||
|
{
|
||||||
|
_cpuContext.InvalidateCacheRegion(address, size);
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (_memoryManager is IRefCounted rc)
|
if (_memoryManager is IRefCounted rc)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Kernel.Common
|
namespace Ryujinx.HLE.HOS.Kernel.Common
|
||||||
{
|
{
|
||||||
@ -41,10 +42,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Common
|
|||||||
range++;
|
range++;
|
||||||
|
|
||||||
// This is log2(Range) plus one.
|
// This is log2(Range) plus one.
|
||||||
int nextRangeLog2 = 64 - BitUtils.CountLeadingZeros64(range);
|
int nextRangeLog2 = 64 - BitOperations.LeadingZeroCount((ulong)range);
|
||||||
|
|
||||||
// If Range is already power of 2, subtract one to use log2(Range) directly.
|
// If Range is already power of 2, subtract one to use log2(Range) directly.
|
||||||
int rangeLog2 = nextRangeLog2 - (BitUtils.IsPowerOfTwo64(range) ? 1 : 0);
|
int rangeLog2 = nextRangeLog2 - (BitOperations.IsPow2(range) ? 1 : 0);
|
||||||
|
|
||||||
int parts = rangeLog2 > 32 ? 2 : 1;
|
int parts = rangeLog2 > 32 ? 2 : 1;
|
||||||
int bitsPerPart = rangeLog2 / parts;
|
int bitsPerPart = rangeLog2 / parts;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Kernel.Memory
|
namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
{
|
{
|
||||||
@ -259,11 +260,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||||||
|
|
||||||
if (backwards)
|
if (backwards)
|
||||||
{
|
{
|
||||||
index = (index * 64 + 63) - BitUtils.CountLeadingZeros64(mask);
|
index = (index * 64 + 63) - BitOperations.LeadingZeroCount((ulong)mask);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
index = index * 64 + BitUtils.CountLeadingZeros64(BitUtils.ReverseBits64(mask));
|
index = index * 64 + BitOperations.LeadingZeroCount((ulong)BitUtils.ReverseBits64(mask));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -312,11 +313,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||||||
|
|
||||||
if (backwards)
|
if (backwards)
|
||||||
{
|
{
|
||||||
index = index * 64 + BitUtils.CountLeadingZeros64(BitUtils.ReverseBits64(mask));
|
index = index * 64 + BitOperations.LeadingZeroCount((ulong)BitUtils.ReverseBits64(mask));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
index = (index * 64 + 63) - BitUtils.CountLeadingZeros64(mask);
|
index = (index * 64 + 63) - BitOperations.LeadingZeroCount((ulong)mask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,5 +9,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||||||
IVirtualMemoryManager AddressSpace { get; }
|
IVirtualMemoryManager AddressSpace { get; }
|
||||||
|
|
||||||
void Execute(ExecutionContext context, ulong codeAddress);
|
void Execute(ExecutionContext context, ulong codeAddress);
|
||||||
|
void InvalidateCacheRegion(ulong address, ulong size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Kernel.Process
|
namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
{
|
{
|
||||||
@ -32,7 +33,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||||||
{
|
{
|
||||||
int mask = _idMasks[index];
|
int mask = _idMasks[index];
|
||||||
|
|
||||||
int firstFreeBit = BitUtils.CountLeadingZeros32((mask + 1) & ~mask);
|
int firstFreeBit = BitOperations.LeadingZeroCount((uint)((mask + 1) & ~mask));
|
||||||
|
|
||||||
if (firstFreeBit < 32)
|
if (firstFreeBit < 32)
|
||||||
{
|
{
|
||||||
|
@ -3,6 +3,7 @@ using Ryujinx.HLE.HOS.Kernel.Common;
|
|||||||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Kernel.Process
|
namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
{
|
{
|
||||||
@ -130,7 +131,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||||||
return KernelResult.Success;
|
return KernelResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
int codeMask = 1 << (32 - BitUtils.CountLeadingZeros32(code + 1));
|
int codeMask = 1 << (32 - BitOperations.LeadingZeroCount((uint)code + 1));
|
||||||
|
|
||||||
// Check if the property was already set.
|
// Check if the property was already set.
|
||||||
if (((mask0 & codeMask) & 0x1e008) != 0)
|
if (((mask0 & codeMask) & 0x1e008) != 0)
|
||||||
|
@ -18,6 +18,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void InvalidateCacheRegion(ulong address, ulong size)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -459,11 +459,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||||||
{
|
{
|
||||||
if (argValues != null)
|
if (argValues != null)
|
||||||
{
|
{
|
||||||
Logger.Debug?.Print(LogClass.KernelSvc, string.Format(formatOrSvcName, argValues));
|
Logger.Trace?.Print(LogClass.KernelSvc, string.Format(formatOrSvcName, argValues));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger.Debug?.Print(LogClass.KernelSvc, formatOrSvcName);
|
Logger.Trace?.Print(LogClass.KernelSvc, formatOrSvcName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -479,7 +479,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger.Debug?.Print(LogClass.KernelSvc, $"{svcName} returned result {result}.");
|
Logger.Trace?.Print(LogClass.KernelSvc, $"{svcName} returned result {result}.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,12 +15,12 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
|||||||
// GetAppletResourceUserId() -> nn::applet::AppletResourceUserId
|
// GetAppletResourceUserId() -> nn::applet::AppletResourceUserId
|
||||||
public ResultCode GetAppletResourceUserId(ServiceCtx context)
|
public ResultCode GetAppletResourceUserId(ServiceCtx context)
|
||||||
{
|
{
|
||||||
Logger.Stub?.PrintStub(LogClass.ServiceAm);
|
|
||||||
|
|
||||||
long appletResourceUserId = context.Device.System.AppletState.AppletResourceUserIds.Add(_pid);
|
long appletResourceUserId = context.Device.System.AppletState.AppletResourceUserIds.Add(_pid);
|
||||||
|
|
||||||
context.ResponseData.Write(appletResourceUserId);
|
context.ResponseData.Write(appletResourceUserId);
|
||||||
|
|
||||||
|
Logger.Stub?.PrintStub(LogClass.ServiceAm, new { appletResourceUserId });
|
||||||
|
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||||||
private bool _vibrationPermitted;
|
private bool _vibrationPermitted;
|
||||||
private bool _usbFullKeyControllerEnabled;
|
private bool _usbFullKeyControllerEnabled;
|
||||||
private bool _isFirmwareUpdateAvailableForSixAxisSensor;
|
private bool _isFirmwareUpdateAvailableForSixAxisSensor;
|
||||||
|
private bool _isSixAxisSensorUnalteredPassthroughEnabled;
|
||||||
|
|
||||||
private HidNpadJoyAssignmentMode _npadJoyAssignmentMode;
|
private HidNpadJoyAssignmentMode _npadJoyAssignmentMode;
|
||||||
private HidNpadHandheldActivationMode _npadHandheldActivationMode;
|
private HidNpadHandheldActivationMode _npadHandheldActivationMode;
|
||||||
@ -335,7 +336,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||||||
// StartSixAxisSensor(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId)
|
// StartSixAxisSensor(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId)
|
||||||
public ResultCode StartSixAxisSensor(ServiceCtx context)
|
public ResultCode StartSixAxisSensor(ServiceCtx context)
|
||||||
{
|
{
|
||||||
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
||||||
|
context.RequestData.BaseStream.Position += 4; // Padding
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
Logger.Stub?.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, sixAxisSensorHandle });
|
Logger.Stub?.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, sixAxisSensorHandle });
|
||||||
@ -347,7 +349,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||||||
// StopSixAxisSensor(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId)
|
// StopSixAxisSensor(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId)
|
||||||
public ResultCode StopSixAxisSensor(ServiceCtx context)
|
public ResultCode StopSixAxisSensor(ServiceCtx context)
|
||||||
{
|
{
|
||||||
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
||||||
|
context.RequestData.BaseStream.Position += 4; // Padding
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
Logger.Stub?.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, sixAxisSensorHandle });
|
Logger.Stub?.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, sixAxisSensorHandle });
|
||||||
@ -359,7 +362,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||||||
// IsSixAxisSensorFusionEnabled(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId) -> bool IsEnabled
|
// IsSixAxisSensorFusionEnabled(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId) -> bool IsEnabled
|
||||||
public ResultCode IsSixAxisSensorFusionEnabled(ServiceCtx context)
|
public ResultCode IsSixAxisSensorFusionEnabled(ServiceCtx context)
|
||||||
{
|
{
|
||||||
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
||||||
|
context.RequestData.BaseStream.Position += 4; // Padding
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
context.ResponseData.Write(_sixAxisSensorFusionEnabled);
|
context.ResponseData.Write(_sixAxisSensorFusionEnabled);
|
||||||
@ -373,9 +377,9 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||||||
// EnableSixAxisSensorFusion(bool Enabled, nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId)
|
// EnableSixAxisSensorFusion(bool Enabled, nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId)
|
||||||
public ResultCode EnableSixAxisSensorFusion(ServiceCtx context)
|
public ResultCode EnableSixAxisSensorFusion(ServiceCtx context)
|
||||||
{
|
{
|
||||||
_sixAxisSensorFusionEnabled = context.RequestData.ReadBoolean();
|
_sixAxisSensorFusionEnabled = context.RequestData.ReadUInt32() != 0;
|
||||||
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
Logger.Stub?.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, sixAxisSensorHandle, _sixAxisSensorFusionEnabled });
|
Logger.Stub?.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, sixAxisSensorHandle, _sixAxisSensorFusionEnabled });
|
||||||
|
|
||||||
@ -386,7 +390,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||||||
// SetSixAxisSensorFusionParameters(nn::hid::SixAxisSensorHandle, float RevisePower, float ReviseRange, nn::applet::AppletResourceUserId)
|
// SetSixAxisSensorFusionParameters(nn::hid::SixAxisSensorHandle, float RevisePower, float ReviseRange, nn::applet::AppletResourceUserId)
|
||||||
public ResultCode SetSixAxisSensorFusionParameters(ServiceCtx context)
|
public ResultCode SetSixAxisSensorFusionParameters(ServiceCtx context)
|
||||||
{
|
{
|
||||||
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
||||||
|
context.RequestData.BaseStream.Position += 4; // Padding
|
||||||
|
|
||||||
_sensorFusionParams = new HidSensorFusionParameters
|
_sensorFusionParams = new HidSensorFusionParameters
|
||||||
{
|
{
|
||||||
@ -405,7 +410,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||||||
// GetSixAxisSensorFusionParameters(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId) -> float RevisePower, float ReviseRange)
|
// GetSixAxisSensorFusionParameters(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId) -> float RevisePower, float ReviseRange)
|
||||||
public ResultCode GetSixAxisSensorFusionParameters(ServiceCtx context)
|
public ResultCode GetSixAxisSensorFusionParameters(ServiceCtx context)
|
||||||
{
|
{
|
||||||
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
||||||
|
context.RequestData.BaseStream.Position += 4; // Padding
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
context.ResponseData.Write(_sensorFusionParams.RevisePower);
|
context.ResponseData.Write(_sensorFusionParams.RevisePower);
|
||||||
@ -420,7 +426,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||||||
// ResetSixAxisSensorFusionParameters(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId)
|
// ResetSixAxisSensorFusionParameters(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId)
|
||||||
public ResultCode ResetSixAxisSensorFusionParameters(ServiceCtx context)
|
public ResultCode ResetSixAxisSensorFusionParameters(ServiceCtx context)
|
||||||
{
|
{
|
||||||
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
||||||
|
context.RequestData.BaseStream.Position += 4; // Padding
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
_sensorFusionParams.RevisePower = 0;
|
_sensorFusionParams.RevisePower = 0;
|
||||||
@ -436,6 +443,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||||||
public ResultCode SetAccelerometerParameters(ServiceCtx context)
|
public ResultCode SetAccelerometerParameters(ServiceCtx context)
|
||||||
{
|
{
|
||||||
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
||||||
|
context.RequestData.BaseStream.Position += 4; // Padding
|
||||||
|
|
||||||
_accelerometerParams = new HidAccelerometerParameters
|
_accelerometerParams = new HidAccelerometerParameters
|
||||||
{
|
{
|
||||||
@ -454,7 +462,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||||||
// GetAccelerometerParameters(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId) -> float X, float Y
|
// GetAccelerometerParameters(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId) -> float X, float Y
|
||||||
public ResultCode GetAccelerometerParameters(ServiceCtx context)
|
public ResultCode GetAccelerometerParameters(ServiceCtx context)
|
||||||
{
|
{
|
||||||
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
||||||
|
context.RequestData.BaseStream.Position += 4; // Padding
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
context.ResponseData.Write(_accelerometerParams.X);
|
context.ResponseData.Write(_accelerometerParams.X);
|
||||||
@ -469,7 +478,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||||||
// ResetAccelerometerParameters(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId)
|
// ResetAccelerometerParameters(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId)
|
||||||
public ResultCode ResetAccelerometerParameters(ServiceCtx context)
|
public ResultCode ResetAccelerometerParameters(ServiceCtx context)
|
||||||
{
|
{
|
||||||
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
||||||
|
context.RequestData.BaseStream.Position += 4; // Padding
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
_accelerometerParams.X = 0;
|
_accelerometerParams.X = 0;
|
||||||
@ -484,9 +494,10 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||||||
// SetAccelerometerPlayMode(nn::hid::SixAxisSensorHandle, uint PlayMode, nn::applet::AppletResourceUserId)
|
// SetAccelerometerPlayMode(nn::hid::SixAxisSensorHandle, uint PlayMode, nn::applet::AppletResourceUserId)
|
||||||
public ResultCode SetAccelerometerPlayMode(ServiceCtx context)
|
public ResultCode SetAccelerometerPlayMode(ServiceCtx context)
|
||||||
{
|
{
|
||||||
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
||||||
_accelerometerPlayMode = context.RequestData.ReadUInt32();
|
context.RequestData.BaseStream.Position += 4; // Padding
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
_accelerometerPlayMode = context.RequestData.ReadUInt32();
|
||||||
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
Logger.Stub?.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, sixAxisSensorHandle, _accelerometerPlayMode });
|
Logger.Stub?.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, sixAxisSensorHandle, _accelerometerPlayMode });
|
||||||
|
|
||||||
@ -497,7 +508,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||||||
// GetAccelerometerPlayMode(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId) -> uint PlayMode
|
// GetAccelerometerPlayMode(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId) -> uint PlayMode
|
||||||
public ResultCode GetAccelerometerPlayMode(ServiceCtx context)
|
public ResultCode GetAccelerometerPlayMode(ServiceCtx context)
|
||||||
{
|
{
|
||||||
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
||||||
|
context.RequestData.BaseStream.Position += 4; // Padding
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
context.ResponseData.Write(_accelerometerPlayMode);
|
context.ResponseData.Write(_accelerometerPlayMode);
|
||||||
@ -511,7 +523,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||||||
// ResetAccelerometerPlayMode(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId)
|
// ResetAccelerometerPlayMode(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId)
|
||||||
public ResultCode ResetAccelerometerPlayMode(ServiceCtx context)
|
public ResultCode ResetAccelerometerPlayMode(ServiceCtx context)
|
||||||
{
|
{
|
||||||
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
||||||
|
context.RequestData.BaseStream.Position += 4; // Padding
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
_accelerometerPlayMode = 0;
|
_accelerometerPlayMode = 0;
|
||||||
@ -525,9 +538,9 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||||||
// SetGyroscopeZeroDriftMode(nn::hid::SixAxisSensorHandle, uint GyroscopeZeroDriftMode, nn::applet::AppletResourceUserId)
|
// SetGyroscopeZeroDriftMode(nn::hid::SixAxisSensorHandle, uint GyroscopeZeroDriftMode, nn::applet::AppletResourceUserId)
|
||||||
public ResultCode SetGyroscopeZeroDriftMode(ServiceCtx context)
|
public ResultCode SetGyroscopeZeroDriftMode(ServiceCtx context)
|
||||||
{
|
{
|
||||||
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
||||||
_gyroscopeZeroDriftMode = (HidGyroscopeZeroDriftMode)context.RequestData.ReadInt32();
|
_gyroscopeZeroDriftMode = (HidGyroscopeZeroDriftMode)context.RequestData.ReadInt32();
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
Logger.Stub?.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, sixAxisSensorHandle, _gyroscopeZeroDriftMode });
|
Logger.Stub?.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, sixAxisSensorHandle, _gyroscopeZeroDriftMode });
|
||||||
|
|
||||||
@ -538,7 +551,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||||||
// GetGyroscopeZeroDriftMode(nn::applet::AppletResourceUserId, nn::hid::SixAxisSensorHandle) -> int GyroscopeZeroDriftMode
|
// GetGyroscopeZeroDriftMode(nn::applet::AppletResourceUserId, nn::hid::SixAxisSensorHandle) -> int GyroscopeZeroDriftMode
|
||||||
public ResultCode GetGyroscopeZeroDriftMode(ServiceCtx context)
|
public ResultCode GetGyroscopeZeroDriftMode(ServiceCtx context)
|
||||||
{
|
{
|
||||||
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
||||||
|
context.RequestData.BaseStream.Position += 4; // Padding
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
context.ResponseData.Write((int)_gyroscopeZeroDriftMode);
|
context.ResponseData.Write((int)_gyroscopeZeroDriftMode);
|
||||||
@ -552,7 +566,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||||||
// ResetGyroscopeZeroDriftMode(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId)
|
// ResetGyroscopeZeroDriftMode(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId)
|
||||||
public ResultCode ResetGyroscopeZeroDriftMode(ServiceCtx context)
|
public ResultCode ResetGyroscopeZeroDriftMode(ServiceCtx context)
|
||||||
{
|
{
|
||||||
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
||||||
|
context.RequestData.BaseStream.Position += 4; // Padding
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
_gyroscopeZeroDriftMode = HidGyroscopeZeroDriftMode.Standard;
|
_gyroscopeZeroDriftMode = HidGyroscopeZeroDriftMode.Standard;
|
||||||
@ -566,7 +581,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||||||
// IsSixAxisSensorAtRest(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId) -> bool IsAsRest
|
// IsSixAxisSensorAtRest(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId) -> bool IsAsRest
|
||||||
public ResultCode IsSixAxisSensorAtRest(ServiceCtx context)
|
public ResultCode IsSixAxisSensorAtRest(ServiceCtx context)
|
||||||
{
|
{
|
||||||
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
||||||
|
context.RequestData.BaseStream.Position += 4; // Padding
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
bool isAtRest = true;
|
bool isAtRest = true;
|
||||||
@ -582,8 +598,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||||||
// IsFirmwareUpdateAvailableForSixAxisSensor(nn::hid::AppletResourceUserId, nn::hid::SixAxisSensorHandle, pid) -> bool UpdateAvailable
|
// IsFirmwareUpdateAvailableForSixAxisSensor(nn::hid::AppletResourceUserId, nn::hid::SixAxisSensorHandle, pid) -> bool UpdateAvailable
|
||||||
public ResultCode IsFirmwareUpdateAvailableForSixAxisSensor(ServiceCtx context)
|
public ResultCode IsFirmwareUpdateAvailableForSixAxisSensor(ServiceCtx context)
|
||||||
{
|
{
|
||||||
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
||||||
context.RequestData.BaseStream.Position += 4;
|
context.RequestData.BaseStream.Position += 4; // Padding
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
context.ResponseData.Write(_isFirmwareUpdateAvailableForSixAxisSensor);
|
context.ResponseData.Write(_isFirmwareUpdateAvailableForSixAxisSensor);
|
||||||
@ -593,6 +609,64 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[CommandHipc(84)] // 13.0.0+
|
||||||
|
// EnableSixAxisSensorUnalteredPassthrough(nn::applet::AppletResourceUserId, nn::hid::SixAxisSensorHandle, u8 enabled)
|
||||||
|
public ResultCode EnableSixAxisSensorUnalteredPassthrough(ServiceCtx context)
|
||||||
|
{
|
||||||
|
_isSixAxisSensorUnalteredPassthroughEnabled = context.RequestData.ReadUInt32() != 0;
|
||||||
|
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
||||||
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
|
Logger.Stub?.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, sixAxisSensorHandle, _isSixAxisSensorUnalteredPassthroughEnabled });
|
||||||
|
|
||||||
|
return ResultCode.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CommandHipc(85)] // 13.0.0+
|
||||||
|
// IsSixAxisSensorUnalteredPassthroughEnabled(nn::applet::AppletResourceUserId, nn::hid::SixAxisSensorHandle) -> u8 enabled
|
||||||
|
public ResultCode IsSixAxisSensorUnalteredPassthroughEnabled(ServiceCtx context)
|
||||||
|
{
|
||||||
|
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
||||||
|
context.RequestData.BaseStream.Position += 4; // Padding
|
||||||
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
|
context.ResponseData.Write(_isSixAxisSensorUnalteredPassthroughEnabled);
|
||||||
|
|
||||||
|
Logger.Stub?.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, sixAxisSensorHandle });
|
||||||
|
|
||||||
|
return ResultCode.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CommandHipc(87)] // 13.0.0+
|
||||||
|
// LoadSixAxisSensorCalibrationParameter(nn::applet::AppletResourceUserId, nn::hid::SixAxisSensorHandle, u64 unknown)
|
||||||
|
public ResultCode LoadSixAxisSensorCalibrationParameter(ServiceCtx context)
|
||||||
|
{
|
||||||
|
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
||||||
|
context.RequestData.BaseStream.Position += 4; // Padding
|
||||||
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
|
// TODO: CalibrationParameter have to be determined.
|
||||||
|
|
||||||
|
Logger.Stub?.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, sixAxisSensorHandle });
|
||||||
|
|
||||||
|
return ResultCode.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CommandHipc(88)] // 13.0.0+
|
||||||
|
// GetSixAxisSensorIcInformation(nn::applet::AppletResourceUserId, nn::hid::SixAxisSensorHandle) -> u64 unknown
|
||||||
|
public ResultCode GetSixAxisSensorIcInformation(ServiceCtx context)
|
||||||
|
{
|
||||||
|
int sixAxisSensorHandle = context.RequestData.ReadInt32();
|
||||||
|
context.RequestData.BaseStream.Position += 4; // Padding
|
||||||
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
|
// TODO: IcInformation have to be determined.
|
||||||
|
|
||||||
|
Logger.Stub?.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, sixAxisSensorHandle });
|
||||||
|
|
||||||
|
return ResultCode.Success;
|
||||||
|
}
|
||||||
|
|
||||||
[CommandHipc(91)]
|
[CommandHipc(91)]
|
||||||
// ActivateGesture(nn::applet::AppletResourceUserId, int Unknown0)
|
// ActivateGesture(nn::applet::AppletResourceUserId, int Unknown0)
|
||||||
public ResultCode ActivateGesture(ServiceCtx context)
|
public ResultCode ActivateGesture(ServiceCtx context)
|
||||||
@ -606,16 +680,15 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||||||
}
|
}
|
||||||
|
|
||||||
[CommandHipc(100)]
|
[CommandHipc(100)]
|
||||||
// SetSupportedNpadStyleSet(nn::applet::AppletResourceUserId, nn::hid::NpadStyleTag)
|
// SetSupportedNpadStyleSet(pid, nn::applet::AppletResourceUserId, nn::hid::NpadStyleTag)
|
||||||
public ResultCode SetSupportedNpadStyleSet(ServiceCtx context)
|
public ResultCode SetSupportedNpadStyleSet(ServiceCtx context)
|
||||||
{
|
{
|
||||||
|
ulong pid = context.Request.HandleDesc.PId;
|
||||||
ControllerType type = (ControllerType)context.RequestData.ReadInt32();
|
ControllerType type = (ControllerType)context.RequestData.ReadInt32();
|
||||||
|
context.RequestData.BaseStream.Position += 4; // Padding
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
Logger.Stub?.PrintStub(LogClass.ServiceHid, new {
|
Logger.Stub?.PrintStub(LogClass.ServiceHid, new { pid, appletResourceUserId, type });
|
||||||
appletResourceUserId,
|
|
||||||
type
|
|
||||||
});
|
|
||||||
|
|
||||||
context.Device.Hid.Npads.SupportedStyleSets = type;
|
context.Device.Hid.Npads.SupportedStyleSets = type;
|
||||||
|
|
||||||
@ -623,17 +696,15 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||||||
}
|
}
|
||||||
|
|
||||||
[CommandHipc(101)]
|
[CommandHipc(101)]
|
||||||
// GetSupportedNpadStyleSet(nn::applet::AppletResourceUserId) -> uint nn::hid::NpadStyleTag
|
// GetSupportedNpadStyleSet(pid, nn::applet::AppletResourceUserId) -> uint nn::hid::NpadStyleTag
|
||||||
public ResultCode GetSupportedNpadStyleSet(ServiceCtx context)
|
public ResultCode GetSupportedNpadStyleSet(ServiceCtx context)
|
||||||
{
|
{
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
ulong pid = context.Request.HandleDesc.PId;
|
||||||
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
context.ResponseData.Write((int)context.Device.Hid.Npads.SupportedStyleSets);
|
context.ResponseData.Write((int)context.Device.Hid.Npads.SupportedStyleSets);
|
||||||
|
|
||||||
Logger.Stub?.PrintStub(LogClass.ServiceHid, new {
|
Logger.Stub?.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, context.Device.Hid.Npads.SupportedStyleSets });
|
||||||
appletResourceUserId,
|
|
||||||
context.Device.Hid.Npads.SupportedStyleSets
|
|
||||||
});
|
|
||||||
|
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
@ -658,7 +729,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.Stub?.PrintStub(LogClass.ServiceHid, $"{supportedPlayerIds.Length} " + string.Join(",", supportedPlayerIds.ToArray()));
|
Logger.Stub?.PrintStub(LogClass.ServiceHid, $"{supportedPlayerIds.Length} Players: " + string.Join(",", supportedPlayerIds.ToArray()));
|
||||||
|
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
@ -117,7 +117,7 @@ namespace Ryujinx.HLE.HOS.Services
|
|||||||
|
|
||||||
if (serviceExists)
|
if (serviceExists)
|
||||||
{
|
{
|
||||||
Logger.Debug?.Print(LogClass.KernelIpc, $"{service.GetType().Name}: {processRequest.Name}");
|
Logger.Trace?.Print(LogClass.KernelIpc, $"{service.GetType().Name}: {processRequest.Name}");
|
||||||
|
|
||||||
result = (ResultCode)processRequest.Invoke(service, new object[] { context });
|
result = (ResultCode)processRequest.Invoke(service, new object[] { context });
|
||||||
}
|
}
|
||||||
|
63
Ryujinx.HLE/HOS/Services/Mnpp/IServiceForApplication.cs
Normal file
63
Ryujinx.HLE/HOS/Services/Mnpp/IServiceForApplication.cs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
using Ryujinx.Common;
|
||||||
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.Cpu;
|
||||||
|
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Services.Mnpp
|
||||||
|
{
|
||||||
|
[Service("mnpp:app")] // 13.0.0+
|
||||||
|
class IServiceForApplication : IpcService
|
||||||
|
{
|
||||||
|
public IServiceForApplication(ServiceCtx context) { }
|
||||||
|
|
||||||
|
[CommandHipc(0)]
|
||||||
|
// Initialize(pid)
|
||||||
|
public ResultCode Initialize(ServiceCtx context)
|
||||||
|
{
|
||||||
|
// Pid placeholder
|
||||||
|
context.RequestData.ReadInt64();
|
||||||
|
ulong pid = context.Request.HandleDesc.PId;
|
||||||
|
|
||||||
|
// TODO: Service calls set:sys GetPlatformRegion.
|
||||||
|
// If the result == 1 (China) it calls arp:r GetApplicationInstanceId and GetApplicationLaunchProperty to get the title id and store it internally.
|
||||||
|
// If not, it does nothing.
|
||||||
|
|
||||||
|
Logger.Stub?.PrintStub(LogClass.ServiceMnpp, new { pid });
|
||||||
|
|
||||||
|
return ResultCode.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CommandHipc(1)]
|
||||||
|
// SendRawTelemetryData(nn::account::Uid user_id, buffer<bytes, 5> title_id)
|
||||||
|
public ResultCode SendRawTelemetryData(ServiceCtx context)
|
||||||
|
{
|
||||||
|
ulong titleIdInputPosition = context.Request.SendBuff[0].Position;
|
||||||
|
ulong titleIdInputSize = context.Request.SendBuff[0].Size;
|
||||||
|
|
||||||
|
UserId userId = context.RequestData.ReadStruct<UserId>();
|
||||||
|
|
||||||
|
// TODO: Service calls set:sys GetPlatformRegion.
|
||||||
|
// If the result != 1 (China) it returns ResultCode.Success.
|
||||||
|
|
||||||
|
if (userId.IsNull)
|
||||||
|
{
|
||||||
|
return ResultCode.InvalidArgument;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (titleIdInputSize <= 64)
|
||||||
|
{
|
||||||
|
string titleId = MemoryHelper.ReadAsciiString(context.Memory, titleIdInputPosition, (long)titleIdInputSize);
|
||||||
|
|
||||||
|
// TODO: The service stores the titleId internally and seems proceed to some telemetry for China, which is not needed here.
|
||||||
|
|
||||||
|
Logger.Stub?.PrintStub(LogClass.ServiceMnpp, new { userId, titleId });
|
||||||
|
|
||||||
|
return ResultCode.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.Stub?.PrintStub(LogClass.ServiceMnpp, new { userId });
|
||||||
|
|
||||||
|
return ResultCode.InvalidBufferSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
13
Ryujinx.HLE/HOS/Services/Mnpp/ResultCode.cs
Normal file
13
Ryujinx.HLE/HOS/Services/Mnpp/ResultCode.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
namespace Ryujinx.HLE.HOS.Services.Mnpp
|
||||||
|
{
|
||||||
|
enum ResultCode
|
||||||
|
{
|
||||||
|
ModuleId = 239,
|
||||||
|
ErrorCodeShift = 9,
|
||||||
|
|
||||||
|
Success = 0,
|
||||||
|
|
||||||
|
InvalidArgument = (100 << ErrorCodeShift) | ModuleId,
|
||||||
|
InvalidBufferSize = (101 << ErrorCodeShift) | ModuleId
|
||||||
|
}
|
||||||
|
}
|
@ -77,7 +77,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
|
|||||||
|
|
||||||
arguments.Handle = CreateHandleFromMap(new NvMapHandle(size));
|
arguments.Handle = CreateHandleFromMap(new NvMapHandle(size));
|
||||||
|
|
||||||
Logger.Info?.Print(LogClass.ServiceNv, $"Created map {arguments.Handle} with size 0x{size:x8}!");
|
Logger.Debug?.Print(LogClass.ServiceNv, $"Created map {arguments.Handle} with size 0x{size:x8}!");
|
||||||
|
|
||||||
return NvInternalResult.Success;
|
return NvInternalResult.Success;
|
||||||
}
|
}
|
||||||
@ -265,7 +265,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
|
|||||||
{
|
{
|
||||||
DeleteMapWithHandle(pid, handle);
|
DeleteMapWithHandle(pid, handle);
|
||||||
|
|
||||||
Logger.Info?.Print(LogClass.ServiceNv, $"Deleted map {handle}!");
|
Logger.Debug?.Print(LogClass.ServiceNv, $"Deleted map {handle}!");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -135,6 +135,9 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
[Option("enable-error-logs", Required = false, Default = true, HelpText = "Enables printing error log messages.")]
|
[Option("enable-error-logs", Required = false, Default = true, HelpText = "Enables printing error log messages.")]
|
||||||
public bool? LoggingEnableError { get; set; }
|
public bool? LoggingEnableError { get; set; }
|
||||||
|
|
||||||
|
[Option("enable-trace-logs", Required = false, Default = false, HelpText = "Enables printing trace log messages.")]
|
||||||
|
public bool? LoggingEnableTrace { get; set; }
|
||||||
|
|
||||||
[Option("enable-guest-logs", Required = false, Default = true, HelpText = "Enables printing guest log messages.")]
|
[Option("enable-guest-logs", Required = false, Default = true, HelpText = "Enables printing guest log messages.")]
|
||||||
public bool? LoggingEnableGuest { get; set; }
|
public bool? LoggingEnableGuest { get; set; }
|
||||||
|
|
||||||
|
@ -389,6 +389,7 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
Logger.SetEnable(LogLevel.Info, (bool)option.LoggingEnableInfo);
|
Logger.SetEnable(LogLevel.Info, (bool)option.LoggingEnableInfo);
|
||||||
Logger.SetEnable(LogLevel.Warning, (bool)option.LoggingEnableWarning);
|
Logger.SetEnable(LogLevel.Warning, (bool)option.LoggingEnableWarning);
|
||||||
Logger.SetEnable(LogLevel.Error, (bool)option.LoggingEnableError);
|
Logger.SetEnable(LogLevel.Error, (bool)option.LoggingEnableError);
|
||||||
|
Logger.SetEnable(LogLevel.Trace, (bool)option.LoggingEnableTrace);
|
||||||
Logger.SetEnable(LogLevel.Guest, (bool)option.LoggingEnableGuest);
|
Logger.SetEnable(LogLevel.Guest, (bool)option.LoggingEnableGuest);
|
||||||
Logger.SetEnable(LogLevel.AccessLog, (bool)option.LoggingEnableFsAccessLog);
|
Logger.SetEnable(LogLevel.AccessLog, (bool)option.LoggingEnableFsAccessLog);
|
||||||
|
|
||||||
|
@ -41,8 +41,8 @@ namespace Ryujinx.Tests.Unicorn
|
|||||||
|
|
||||||
public uint PC
|
public uint PC
|
||||||
{
|
{
|
||||||
get => GetRegister(Arm32Register.PC);
|
get => GetRegister(Arm32Register.PC) & 0xfffffffeu;
|
||||||
set => SetRegister(Arm32Register.PC, value);
|
set => SetRegister(Arm32Register.PC, (value & 0xfffffffeu) | (ThumbFlag ? 1u : 0u));
|
||||||
}
|
}
|
||||||
|
|
||||||
public uint CPSR
|
public uint CPSR
|
||||||
@ -87,6 +87,16 @@ namespace Ryujinx.Tests.Unicorn
|
|||||||
set => CPSR = (CPSR & ~0x80000000u) | (value ? 0x80000000u : 0u);
|
set => CPSR = (CPSR & ~0x80000000u) | (value ? 0x80000000u : 0u);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool ThumbFlag
|
||||||
|
{
|
||||||
|
get => (CPSR & 0x00000020u) != 0;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
CPSR = (CPSR & ~0x00000020u) | (value ? 0x00000020u : 0u);
|
||||||
|
SetRegister(Arm32Register.PC, (GetRegister(Arm32Register.PC) & 0xfffffffeu) | (value ? 1u : 0u));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public UnicornAArch32()
|
public UnicornAArch32()
|
||||||
{
|
{
|
||||||
Interface.Checked(Interface.uc_open(UnicornArch.UC_ARCH_ARM, UnicornMode.UC_MODE_LITTLE_ENDIAN, out uc));
|
Interface.Checked(Interface.uc_open(UnicornArch.UC_ARCH_ARM, UnicornMode.UC_MODE_LITTLE_ENDIAN, out uc));
|
||||||
|
@ -106,6 +106,18 @@ namespace Ryujinx.Tests.Cpu
|
|||||||
_currAddress += 4;
|
_currAddress += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void ThumbOpcode(ushort opcode)
|
||||||
|
{
|
||||||
|
_memory.Write(_currAddress, opcode);
|
||||||
|
|
||||||
|
if (_unicornAvailable)
|
||||||
|
{
|
||||||
|
_unicornEmu.MemoryWrite16(_currAddress, opcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
_currAddress += 2;
|
||||||
|
}
|
||||||
|
|
||||||
protected ExecutionContext GetContext() => _context;
|
protected ExecutionContext GetContext() => _context;
|
||||||
|
|
||||||
protected void SetContext(uint r0 = 0,
|
protected void SetContext(uint r0 = 0,
|
||||||
@ -126,7 +138,8 @@ namespace Ryujinx.Tests.Cpu
|
|||||||
bool carry = false,
|
bool carry = false,
|
||||||
bool zero = false,
|
bool zero = false,
|
||||||
bool negative = false,
|
bool negative = false,
|
||||||
int fpscr = 0)
|
int fpscr = 0,
|
||||||
|
bool thumb = false)
|
||||||
{
|
{
|
||||||
_context.SetX(0, r0);
|
_context.SetX(0, r0);
|
||||||
_context.SetX(1, r1);
|
_context.SetX(1, r1);
|
||||||
@ -151,6 +164,8 @@ namespace Ryujinx.Tests.Cpu
|
|||||||
|
|
||||||
SetFpscr((uint)fpscr);
|
SetFpscr((uint)fpscr);
|
||||||
|
|
||||||
|
_context.SetPstateFlag(PState.TFlag, thumb);
|
||||||
|
|
||||||
if (_unicornAvailable)
|
if (_unicornAvailable)
|
||||||
{
|
{
|
||||||
_unicornEmu.R[0] = r0;
|
_unicornEmu.R[0] = r0;
|
||||||
@ -175,6 +190,8 @@ namespace Ryujinx.Tests.Cpu
|
|||||||
_unicornEmu.NegativeFlag = negative;
|
_unicornEmu.NegativeFlag = negative;
|
||||||
|
|
||||||
_unicornEmu.Fpscr = fpscr;
|
_unicornEmu.Fpscr = fpscr;
|
||||||
|
|
||||||
|
_unicornEmu.ThumbFlag = thumb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,6 +235,28 @@ namespace Ryujinx.Tests.Cpu
|
|||||||
return GetContext();
|
return GetContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected ExecutionContext SingleThumbOpcode(ushort opcode,
|
||||||
|
uint r0 = 0,
|
||||||
|
uint r1 = 0,
|
||||||
|
uint r2 = 0,
|
||||||
|
uint r3 = 0,
|
||||||
|
uint sp = 0,
|
||||||
|
bool saturation = false,
|
||||||
|
bool overflow = false,
|
||||||
|
bool carry = false,
|
||||||
|
bool zero = false,
|
||||||
|
bool negative = false,
|
||||||
|
int fpscr = 0,
|
||||||
|
bool runUnicorn = true)
|
||||||
|
{
|
||||||
|
ThumbOpcode(opcode);
|
||||||
|
ThumbOpcode(0x4770); // BX LR
|
||||||
|
SetContext(r0, r1, r2, r3, sp, default, default, default, default, default, default, default, default, saturation, overflow, carry, zero, negative, fpscr, thumb: true);
|
||||||
|
ExecuteOpcodes(runUnicorn);
|
||||||
|
|
||||||
|
return GetContext();
|
||||||
|
}
|
||||||
|
|
||||||
protected void SetWorkingMemory(uint offset, byte[] data)
|
protected void SetWorkingMemory(uint offset, byte[] data)
|
||||||
{
|
{
|
||||||
_memory.Write(DataBaseAddress + offset, data);
|
_memory.Write(DataBaseAddress + offset, data);
|
||||||
|
915
Ryujinx.Tests/Cpu/CpuTestThumb.cs
Normal file
915
Ryujinx.Tests/Cpu/CpuTestThumb.cs
Normal file
File diff suppressed because one or more lines are too long
@ -14,7 +14,7 @@ namespace Ryujinx.Configuration
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current version of the file format
|
/// The current version of the file format
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const int CurrentVersion = 35;
|
public const int CurrentVersion = 36;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Version of the configuration file format
|
/// Version of the configuration file format
|
||||||
@ -81,6 +81,11 @@ namespace Ryujinx.Configuration
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool LoggingEnableError { get; set; }
|
public bool LoggingEnableError { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables printing trace log messages
|
||||||
|
/// </summary>
|
||||||
|
public bool LoggingEnableTrace { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enables printing guest log messages
|
/// Enables printing guest log messages
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -129,6 +129,11 @@ namespace Ryujinx.Configuration
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public ReactiveObject<bool> EnableError { get; private set; }
|
public ReactiveObject<bool> EnableError { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables printing trace log messages
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> EnableTrace { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enables printing guest log messages
|
/// Enables printing guest log messages
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -161,6 +166,7 @@ namespace Ryujinx.Configuration
|
|||||||
EnableInfo = new ReactiveObject<bool>();
|
EnableInfo = new ReactiveObject<bool>();
|
||||||
EnableWarn = new ReactiveObject<bool>();
|
EnableWarn = new ReactiveObject<bool>();
|
||||||
EnableError = new ReactiveObject<bool>();
|
EnableError = new ReactiveObject<bool>();
|
||||||
|
EnableTrace = new ReactiveObject<bool>();
|
||||||
EnableGuest = new ReactiveObject<bool>();
|
EnableGuest = new ReactiveObject<bool>();
|
||||||
EnableFsAccessLog = new ReactiveObject<bool>();
|
EnableFsAccessLog = new ReactiveObject<bool>();
|
||||||
FilteredClasses = new ReactiveObject<LogClass[]>();
|
FilteredClasses = new ReactiveObject<LogClass[]>();
|
||||||
@ -455,6 +461,7 @@ namespace Ryujinx.Configuration
|
|||||||
LoggingEnableInfo = Logger.EnableInfo,
|
LoggingEnableInfo = Logger.EnableInfo,
|
||||||
LoggingEnableWarn = Logger.EnableWarn,
|
LoggingEnableWarn = Logger.EnableWarn,
|
||||||
LoggingEnableError = Logger.EnableError,
|
LoggingEnableError = Logger.EnableError,
|
||||||
|
LoggingEnableTrace = Logger.EnableTrace,
|
||||||
LoggingEnableGuest = Logger.EnableGuest,
|
LoggingEnableGuest = Logger.EnableGuest,
|
||||||
LoggingEnableFsAccessLog = Logger.EnableFsAccessLog,
|
LoggingEnableFsAccessLog = Logger.EnableFsAccessLog,
|
||||||
LoggingFilteredClasses = Logger.FilteredClasses,
|
LoggingFilteredClasses = Logger.FilteredClasses,
|
||||||
@ -526,6 +533,7 @@ namespace Ryujinx.Configuration
|
|||||||
Logger.EnableInfo.Value = true;
|
Logger.EnableInfo.Value = true;
|
||||||
Logger.EnableWarn.Value = true;
|
Logger.EnableWarn.Value = true;
|
||||||
Logger.EnableError.Value = true;
|
Logger.EnableError.Value = true;
|
||||||
|
Logger.EnableTrace.Value = false;
|
||||||
Logger.EnableGuest.Value = true;
|
Logger.EnableGuest.Value = true;
|
||||||
Logger.EnableFsAccessLog.Value = false;
|
Logger.EnableFsAccessLog.Value = false;
|
||||||
Logger.FilteredClasses.Value = Array.Empty<LogClass>();
|
Logger.FilteredClasses.Value = Array.Empty<LogClass>();
|
||||||
@ -990,6 +998,15 @@ namespace Ryujinx.Configuration
|
|||||||
|
|
||||||
configurationFileUpdated = true;
|
configurationFileUpdated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 36)
|
||||||
|
{
|
||||||
|
Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 36.");
|
||||||
|
|
||||||
|
configurationFileFormat.LoggingEnableTrace = false;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
Logger.EnableFileLog.Value = configurationFileFormat.EnableFileLog;
|
Logger.EnableFileLog.Value = configurationFileFormat.EnableFileLog;
|
||||||
Graphics.BackendThreading.Value = configurationFileFormat.BackendThreading;
|
Graphics.BackendThreading.Value = configurationFileFormat.BackendThreading;
|
||||||
@ -1003,6 +1020,7 @@ namespace Ryujinx.Configuration
|
|||||||
Logger.EnableInfo.Value = configurationFileFormat.LoggingEnableInfo;
|
Logger.EnableInfo.Value = configurationFileFormat.LoggingEnableInfo;
|
||||||
Logger.EnableWarn.Value = configurationFileFormat.LoggingEnableWarn;
|
Logger.EnableWarn.Value = configurationFileFormat.LoggingEnableWarn;
|
||||||
Logger.EnableError.Value = configurationFileFormat.LoggingEnableError;
|
Logger.EnableError.Value = configurationFileFormat.LoggingEnableError;
|
||||||
|
Logger.EnableTrace.Value = configurationFileFormat.LoggingEnableTrace;
|
||||||
Logger.EnableGuest.Value = configurationFileFormat.LoggingEnableGuest;
|
Logger.EnableGuest.Value = configurationFileFormat.LoggingEnableGuest;
|
||||||
Logger.EnableFsAccessLog.Value = configurationFileFormat.LoggingEnableFsAccessLog;
|
Logger.EnableFsAccessLog.Value = configurationFileFormat.LoggingEnableFsAccessLog;
|
||||||
Logger.FilteredClasses.Value = configurationFileFormat.LoggingFilteredClasses;
|
Logger.FilteredClasses.Value = configurationFileFormat.LoggingFilteredClasses;
|
||||||
|
@ -13,6 +13,7 @@ namespace Ryujinx.Configuration
|
|||||||
ConfigurationState.Instance.Logger.EnableInfo.Event += ReloadEnableInfo;
|
ConfigurationState.Instance.Logger.EnableInfo.Event += ReloadEnableInfo;
|
||||||
ConfigurationState.Instance.Logger.EnableWarn.Event += ReloadEnableWarning;
|
ConfigurationState.Instance.Logger.EnableWarn.Event += ReloadEnableWarning;
|
||||||
ConfigurationState.Instance.Logger.EnableError.Event += ReloadEnableError;
|
ConfigurationState.Instance.Logger.EnableError.Event += ReloadEnableError;
|
||||||
|
ConfigurationState.Instance.Logger.EnableTrace.Event += ReloadEnableTrace;
|
||||||
ConfigurationState.Instance.Logger.EnableGuest.Event += ReloadEnableGuest;
|
ConfigurationState.Instance.Logger.EnableGuest.Event += ReloadEnableGuest;
|
||||||
ConfigurationState.Instance.Logger.EnableFsAccessLog.Event += ReloadEnableFsAccessLog;
|
ConfigurationState.Instance.Logger.EnableFsAccessLog.Event += ReloadEnableFsAccessLog;
|
||||||
ConfigurationState.Instance.Logger.FilteredClasses.Event += ReloadFilteredClasses;
|
ConfigurationState.Instance.Logger.FilteredClasses.Event += ReloadFilteredClasses;
|
||||||
@ -44,6 +45,11 @@ namespace Ryujinx.Configuration
|
|||||||
Logger.SetEnable(LogLevel.Error, e.NewValue);
|
Logger.SetEnable(LogLevel.Error, e.NewValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void ReloadEnableTrace(object sender, ReactiveEventArgs<bool> e)
|
||||||
|
{
|
||||||
|
Logger.SetEnable(LogLevel.Trace, e.NewValue);
|
||||||
|
}
|
||||||
|
|
||||||
private static void ReloadEnableGuest(object sender, ReactiveEventArgs<bool> e)
|
private static void ReloadEnableGuest(object sender, ReactiveEventArgs<bool> e)
|
||||||
{
|
{
|
||||||
Logger.SetEnable(LogLevel.Guest, e.NewValue);
|
Logger.SetEnable(LogLevel.Guest, e.NewValue);
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user