Compare commits
19 Commits
Author | SHA1 | Date | |
---|---|---|---|
72e543e946 | |||
98c838b24c | |||
63c9c64196 | |||
a113ed0811 | |||
747876dc67 | |||
95cc18a7b4 | |||
c017c77365 | |||
98e05ee4b7 | |||
868919e101 | |||
9ca040c0ff | |||
7e9011673b | |||
741db8e43d | |||
3bd357045f | |||
ab5d77c0c4 | |||
7bfb5f79b8 | |||
8cc2479825 | |||
8f35345729 | |||
ce71f9144e | |||
f861f0bca2 |
3
.gitignore
vendored
3
.gitignore
vendored
@ -74,6 +74,9 @@ _TeamCity*
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# Rider is a Visual Studio alternative
|
||||
.idea/*
|
||||
|
||||
# NCrunch
|
||||
*.ncrunch*
|
||||
.*crunch*.local.xml
|
||||
|
@ -195,12 +195,13 @@ namespace ARMeilleure.Decoders
|
||||
ulong limitAddress)
|
||||
{
|
||||
ulong address = block.Address;
|
||||
int itBlockSize = 0;
|
||||
|
||||
OpCode opCode;
|
||||
|
||||
do
|
||||
{
|
||||
if (address >= limitAddress)
|
||||
if (address >= limitAddress && itBlockSize == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
@ -210,6 +211,15 @@ namespace ARMeilleure.Decoders
|
||||
block.OpCodes.Add(opCode);
|
||||
|
||||
address += (ulong)opCode.OpCodeSizeInBytes;
|
||||
|
||||
if (opCode is OpCodeT16IfThen it)
|
||||
{
|
||||
itBlockSize = it.IfThenBlockSize;
|
||||
}
|
||||
else if (itBlockSize > 0)
|
||||
{
|
||||
itBlockSize--;
|
||||
}
|
||||
}
|
||||
while (!(IsBranch(opCode) || IsException(opCode)));
|
||||
|
||||
@ -345,7 +355,14 @@ namespace ARMeilleure.Decoders
|
||||
}
|
||||
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
|
||||
{
|
||||
interface IOpCode32Alu : IOpCode32
|
||||
interface IOpCode32Alu : IOpCode32, IOpCode32HasSetFlags
|
||||
{
|
||||
int Rd { 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 IsLoad { get; }
|
||||
bool Index { get; }
|
||||
bool Add { get; }
|
||||
|
||||
int Immediate { get; }
|
||||
}
|
||||
}
|
@ -9,5 +9,7 @@ namespace ARMeilleure.Decoders
|
||||
int PostOffset { 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)
|
||||
{
|
||||
Address = address;
|
||||
RawOpCode = opCode;
|
||||
|
||||
Instruction = inst;
|
||||
Address = address;
|
||||
RawOpCode = opCode;
|
||||
|
||||
RegisterSize = RegisterSize.Int64;
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ namespace ARMeilleure.Decoders
|
||||
public int Rd { 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);
|
||||
|
||||
|
@ -2,7 +2,7 @@ using ARMeilleure.Common;
|
||||
|
||||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
class OpCode32AluImm : OpCode32Alu
|
||||
class OpCode32AluImm : OpCode32Alu, IOpCode32AluImm
|
||||
{
|
||||
public int Immediate { get; }
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
public bool NHigh { get; }
|
||||
public bool MHigh { 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);
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
class OpCode32AluRsImm : OpCode32Alu
|
||||
class OpCode32AluRsImm : OpCode32Alu, IOpCode32AluRsImm
|
||||
{
|
||||
public int Rm { get; }
|
||||
public int Immediate { get; }
|
||||
|
@ -1,6 +1,6 @@
|
||||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
class OpCode32AluRsReg : OpCode32Alu
|
||||
class OpCode32AluRsReg : OpCode32Alu, IOpCode32AluRsReg
|
||||
{
|
||||
public int Rm { get; }
|
||||
public int Rs { get; }
|
||||
|
@ -1,6 +1,6 @@
|
||||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
class OpCode32AluUmull : OpCode32
|
||||
class OpCode32AluUmull : OpCode32, IOpCode32HasSetFlags
|
||||
{
|
||||
public int RdLo { get; }
|
||||
public int RdHi { get; }
|
||||
@ -10,7 +10,7 @@
|
||||
public bool NHigh { get; }
|
||||
public bool MHigh { get; }
|
||||
|
||||
public bool SetFlags { get; }
|
||||
public bool? SetFlags { get; }
|
||||
public DataOp DataOp { get; }
|
||||
|
||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32AluUmull(inst, address, opCode);
|
||||
|
@ -1,6 +1,6 @@
|
||||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
class OpCode32Exception : OpCode32
|
||||
class OpCode32Exception : OpCode32, IOpCode32Exception
|
||||
{
|
||||
public int Id { get; }
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
class OpCode32MemReg : OpCode32Mem
|
||||
class OpCode32MemReg : OpCode32Mem, IOpCode32MemReg
|
||||
{
|
||||
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 int Rn => _rdn;
|
||||
|
||||
public bool SetFlags => false;
|
||||
public bool? SetFlags => null;
|
||||
|
||||
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)
|
||||
{
|
||||
Rd = (opCode >> 8) & 0x7;
|
||||
Rn = (opCode >> 8) & 0x7;
|
||||
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
|
||||
{
|
||||
@ -11,4 +11,4 @@ namespace ARMeilleure.Decoders
|
||||
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.State;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@ -29,9 +28,9 @@ namespace ARMeilleure.Decoders
|
||||
}
|
||||
}
|
||||
|
||||
private static List<InstInfo> AllInstA32 = new List<InstInfo>();
|
||||
private static List<InstInfo> AllInstT32 = new List<InstInfo>();
|
||||
private static List<InstInfo> AllInstA64 = new List<InstInfo>();
|
||||
private static List<InstInfo> AllInstA32 = new();
|
||||
private static List<InstInfo> AllInstT32 = new();
|
||||
private static List<InstInfo> AllInstA64 = new();
|
||||
|
||||
private static InstInfo[][] InstA32FastLookup = 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);
|
||||
#endregion
|
||||
|
||||
#region "OpCode Table (AArch32)"
|
||||
#region "OpCode Table (AArch32, A32)"
|
||||
// Base
|
||||
SetA32("<<<<0010101xxxxxxxxxxxxxxxxxxxxx", InstName.Adc, InstEmit32.Adc, OpCode32AluImm.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("<<<<000100101111111111110011xxxx", InstName.Blx, InstEmit32.Blxr, 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("<<<<000101101111xxxx11110001xxxx", InstName.Clz, InstEmit32.Clz, OpCode32AluReg.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("<<<<0001101x0000xxxxxxxx0xx1xxxx", InstName.Mov, InstEmit32.Mov, OpCode32AluRsReg.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("<<<<1110xxx1xxxxxxxx111xxxx1xxxx", InstName.Mrc, InstEmit32.Mrc, 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);
|
||||
#endregion
|
||||
|
||||
FillFastLookupTable(InstA32FastLookup, AllInstA32);
|
||||
FillFastLookupTable(InstT32FastLookup, AllInstT32);
|
||||
FillFastLookupTable(InstA64FastLookup, AllInstA64);
|
||||
#region "OpCode Table (AArch32, T16/T32)"
|
||||
// T16
|
||||
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];
|
||||
|
||||
@ -1011,20 +1081,27 @@ namespace ARMeilleure.Decoders
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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 value = 0;
|
||||
@ -1073,7 +1150,7 @@ namespace ARMeilleure.Decoders
|
||||
|
||||
if (xBits == 0)
|
||||
{
|
||||
InsertInst(new InstInfo(xMask, value, inst, makeOp), mode);
|
||||
list.Add(new InstInfo(xMask, value, inst, makeOp));
|
||||
|
||||
return;
|
||||
}
|
||||
@ -1089,34 +1166,24 @@ namespace ARMeilleure.Decoders
|
||||
|
||||
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)
|
||||
{
|
||||
return GetInstFromList(InstA32FastLookup[ToFastLookupIndex(opCode)], opCode);
|
||||
return GetInstFromList(InstA32FastLookup[ToFastLookupIndexA(opCode)], 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)
|
||||
{
|
||||
return GetInstFromList(InstA64FastLookup[ToFastLookupIndex(opCode)], opCode);
|
||||
return GetInstFromList(InstA64FastLookup[ToFastLookupIndexA(opCode)], 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);
|
||||
}
|
||||
|
||||
private static int ToFastLookupIndex(int value)
|
||||
private static int ToFastLookupIndexA(int value)
|
||||
{
|
||||
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
|
||||
|
||||
using ARMeilleure.State;
|
||||
using System;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
static class CryptoHelper
|
||||
{
|
||||
#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,
|
||||
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
|
||||
};
|
||||
|
||||
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,
|
||||
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
|
||||
};
|
||||
|
||||
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,
|
||||
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
|
||||
};
|
||||
|
||||
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,
|
||||
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
|
||||
};
|
||||
|
||||
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,
|
||||
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
|
||||
};
|
||||
|
||||
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,
|
||||
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
|
||||
};
|
||||
|
||||
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,
|
||||
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
|
||||
};
|
||||
|
||||
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,
|
||||
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
|
||||
};
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
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
|
||||
};
|
||||
|
@ -20,7 +20,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
Operand res = context.Add(n, m);
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
|
||||
@ -44,7 +44,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
res = context.Add(res, carry);
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
|
||||
@ -64,7 +64,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
Operand res = context.BitwiseAnd(n, m);
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
}
|
||||
@ -110,7 +110,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
Operand res = context.BitwiseAnd(n, context.BitwiseNot(m));
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
}
|
||||
@ -161,7 +161,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
Operand res = context.BitwiseExclusiveOr(n, m);
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
}
|
||||
@ -175,7 +175,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
Operand m = GetAluM(context);
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, m);
|
||||
}
|
||||
@ -204,7 +204,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
Operand res = context.Multiply(n, m);
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
}
|
||||
@ -219,7 +219,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
Operand res = context.BitwiseNot(m);
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
}
|
||||
@ -236,7 +236,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
Operand res = context.BitwiseOr(n, m);
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
}
|
||||
@ -315,7 +315,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
res = context.Subtract(res, borrow);
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
|
||||
@ -335,7 +335,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
Operand res = context.Subtract(m, n);
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
|
||||
@ -359,7 +359,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
res = context.Subtract(res, borrow);
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
|
||||
@ -420,7 +420,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
Operand res = context.Subtract(n, m);
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
|
||||
@ -836,7 +836,7 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
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
|
||||
{
|
||||
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)
|
||||
{
|
||||
SetFlag(context, PState.NFlag, context.ICompareLess (d, Const(d.Type, 0)));
|
||||
@ -183,9 +195,9 @@ namespace ARMeilleure.Instructions
|
||||
switch (context.CurrOp)
|
||||
{
|
||||
// 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));
|
||||
}
|
||||
@ -195,10 +207,8 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
case OpCode32AluImm16 op: return Const(op.Immediate);
|
||||
|
||||
case OpCode32AluRsImm op: return GetMShiftedByImmediate(context, op, setCarry);
|
||||
case OpCode32AluRsReg op: return GetMShiftedByReg(context, op, setCarry);
|
||||
|
||||
case OpCodeT16AluImm8 op: return Const(op.Immediate);
|
||||
case IOpCode32AluRsImm op: return GetMShiftedByImmediate(context, op, setCarry);
|
||||
case IOpCode32AluRsReg op: return GetMShiftedByReg(context, op, setCarry);
|
||||
|
||||
case IOpCode32AluReg op: return GetIntA32(context, op.Rm);
|
||||
|
||||
@ -249,7 +259,7 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
@ -267,7 +277,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
if (shift != 0)
|
||||
{
|
||||
setCarry &= op.SetFlags;
|
||||
setCarry &= ShouldSetFlags(context);
|
||||
|
||||
switch (op.ShiftType)
|
||||
{
|
||||
@ -305,7 +315,7 @@ namespace ARMeilleure.Instructions
|
||||
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 s = context.ZeroExtend8(OperandType.I32, GetIntA32(context, op.Rs));
|
||||
@ -314,7 +324,7 @@ namespace ARMeilleure.Instructions
|
||||
Operand zeroResult = m;
|
||||
Operand shiftResult = m;
|
||||
|
||||
setCarry &= op.SetFlags;
|
||||
setCarry &= ShouldSetFlags(context);
|
||||
|
||||
switch (op.ShiftType)
|
||||
{
|
||||
|
@ -20,11 +20,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
private static void EmitExceptionCall(ArmEmitterContext context, string name)
|
||||
{
|
||||
OpCode32Exception op = (OpCode32Exception)context.CurrOp;
|
||||
IOpCode32Exception op = (IOpCode32Exception)context.CurrOp;
|
||||
|
||||
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();
|
||||
|
||||
|
@ -64,7 +64,7 @@ namespace ARMeilleure.Instructions
|
||||
bool isThumb = IsThumb(context.CurrOp);
|
||||
|
||||
uint currentPc = isThumb
|
||||
? pc | 1
|
||||
? (pc - 2) | 1
|
||||
: pc - 4;
|
||||
|
||||
SetIntA32(context, GetBankedRegisterAlias(context.Mode, RegisterAlias.Aarch32Lr), Const(currentPc));
|
||||
@ -80,5 +80,32 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
@ -47,6 +47,20 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
}
|
||||
|
||||
public static Operand GetIntA32AlignedPC(ArmEmitterContext context, int regIndex)
|
||||
{
|
||||
if (regIndex == RegisterAlias.Aarch32Pc)
|
||||
{
|
||||
OpCode32 op = (OpCode32)context.CurrOp;
|
||||
|
||||
return Const((int)(op.GetPc() & 0xfffffffc));
|
||||
}
|
||||
else
|
||||
{
|
||||
return Register(GetRegisterAlias(context.Mode, regIndex), RegisterType.Integer, OperandType.I32);
|
||||
}
|
||||
}
|
||||
|
||||
public static Operand GetVecA32(int regIndex)
|
||||
{
|
||||
return Register(regIndex, RegisterType.Vector, OperandType.V128);
|
||||
|
@ -32,7 +32,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Ldm(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32MemMult op = (OpCode32MemMult)context.CurrOp;
|
||||
IOpCode32MemMult op = (IOpCode32MemMult)context.CurrOp;
|
||||
|
||||
Operand n = GetIntA32(context, op.Rn);
|
||||
|
||||
@ -95,7 +95,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Stm(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32MemMult op = (OpCode32MemMult)context.CurrOp;
|
||||
IOpCode32MemMult op = (IOpCode32MemMult)context.CurrOp;
|
||||
|
||||
Operand n = context.Copy(GetIntA32(context, op.Rn));
|
||||
|
||||
@ -151,9 +151,9 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
private static void EmitLoadOrStore(ArmEmitterContext context, int size, AccessType accType)
|
||||
{
|
||||
OpCode32Mem op = (OpCode32Mem)context.CurrOp;
|
||||
IOpCode32Mem op = (IOpCode32Mem)context.CurrOp;
|
||||
|
||||
Operand n = context.Copy(GetIntA32(context, op.Rn));
|
||||
Operand n = context.Copy(GetIntA32AlignedPC(context, op.Rn));
|
||||
Operand m = GetMemM(context, setCarry: false);
|
||||
|
||||
Operand temp = default;
|
||||
@ -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 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);
|
||||
|
||||
|
@ -33,7 +33,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
Operand res = context.Add(a, context.Multiply(n, m));
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
}
|
||||
@ -250,13 +250,13 @@ namespace ARMeilleure.Instructions
|
||||
Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32)));
|
||||
Operand lo = context.ConvertI64ToI32(res);
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
}
|
||||
|
||||
EmitGenericAluStoreA32(context, op.RdHi, op.SetFlags, hi);
|
||||
EmitGenericAluStoreA32(context, op.RdLo, op.SetFlags, lo);
|
||||
EmitGenericAluStoreA32(context, op.RdHi, ShouldSetFlags(context), hi);
|
||||
EmitGenericAluStoreA32(context, op.RdLo, ShouldSetFlags(context), lo);
|
||||
}
|
||||
|
||||
public static void Smulw_(ArmEmitterContext context)
|
||||
@ -320,13 +320,13 @@ namespace ARMeilleure.Instructions
|
||||
Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32)));
|
||||
Operand lo = context.ConvertI64ToI32(res);
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
}
|
||||
|
||||
EmitGenericAluStoreA32(context, op.RdHi, op.SetFlags, hi);
|
||||
EmitGenericAluStoreA32(context, op.RdLo, op.SetFlags, lo);
|
||||
EmitGenericAluStoreA32(context, op.RdHi, ShouldSetFlags(context), hi);
|
||||
EmitGenericAluStoreA32(context, op.RdLo, ShouldSetFlags(context), lo);
|
||||
}
|
||||
|
||||
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 lo = context.ConvertI64ToI32(res);
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
}
|
||||
|
||||
EmitGenericAluStoreA32(context, op.RdHi, op.SetFlags, hi);
|
||||
EmitGenericAluStoreA32(context, op.RdLo, op.SetFlags, lo);
|
||||
EmitGenericAluStoreA32(context, op.RdHi, ShouldSetFlags(context), hi);
|
||||
EmitGenericAluStoreA32(context, op.RdLo, ShouldSetFlags(context), lo);
|
||||
}
|
||||
|
||||
private static void UpdateQFlag(ArmEmitterContext context, Operand q)
|
||||
|
@ -48,6 +48,7 @@ namespace ARMeilleure.Instructions
|
||||
Extr,
|
||||
Hint,
|
||||
Isb,
|
||||
It,
|
||||
Ldar,
|
||||
Ldaxp,
|
||||
Ldaxr,
|
||||
@ -512,6 +513,8 @@ namespace ARMeilleure.Instructions
|
||||
Mvn,
|
||||
Pkh,
|
||||
Pld,
|
||||
Pop,
|
||||
Push,
|
||||
Rev,
|
||||
Revsh,
|
||||
Rsb,
|
||||
|
@ -824,7 +824,7 @@ namespace ARMeilleure.Instructions
|
||||
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.).
|
||||
{
|
||||
|
@ -54,6 +54,11 @@ namespace ARMeilleure.Translation
|
||||
public bool HighCq { 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(
|
||||
IMemoryManager memory,
|
||||
EntryTable<uint> countTable,
|
||||
@ -196,5 +201,19 @@ namespace ARMeilleure.Translation
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
public void SetIfThenBlockState(Condition[] state)
|
||||
{
|
||||
_ifThenBlockState = state;
|
||||
_ifThenBlockStateIndex = 0;
|
||||
}
|
||||
|
||||
public void AdvanceIfThenBlockState()
|
||||
{
|
||||
if (IsInIfThenBlock)
|
||||
{
|
||||
_ifThenBlockStateIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -380,6 +380,13 @@ namespace ARMeilleure.Translation
|
||||
|
||||
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)
|
||||
{
|
||||
lblPredicateSkip = Label();
|
||||
@ -400,6 +407,11 @@ namespace ARMeilleure.Translation
|
||||
{
|
||||
context.MarkLabel(lblPredicateSkip);
|
||||
}
|
||||
|
||||
if (context.IsInIfThenBlock && opCode.Instruction.Name != InstName.It)
|
||||
{
|
||||
context.AdvanceIfThenBlockState();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -100,9 +100,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
{
|
||||
for (int sampleIndex = 0; sampleIndex < context.SampleCount; sampleIndex++)
|
||||
{
|
||||
float inputSample = *((float*)inputBuffers[channelIndex] + sampleIndex);
|
||||
float rawInputSample = *((float*)inputBuffers[channelIndex] + sampleIndex);
|
||||
|
||||
float sampleInputMax = Math.Abs(inputSample * Parameter.InputGain);
|
||||
float inputSample = (rawInputSample / short.MaxValue) * Parameter.InputGain;
|
||||
|
||||
float sampleInputMax = Math.Abs(inputSample);
|
||||
|
||||
float inputCoefficient = Parameter.ReleaseCoefficient;
|
||||
|
||||
@ -131,7 +133,9 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
ref float delayedSample = ref state.DelayedSampleBuffer[channelIndex * Parameter.DelayBufferSampleCountMax + state.DelayedSampleBufferPosition[channelIndex]];
|
||||
|
||||
*((float*)outputBuffers[channelIndex] + sampleIndex) = delayedSample * state.CompressionGain[channelIndex] * Parameter.OutputGain;
|
||||
float outputSample = delayedSample * state.CompressionGain[channelIndex] * Parameter.OutputGain;
|
||||
|
||||
*((float*)outputBuffers[channelIndex] + sampleIndex) = outputSample * short.MaxValue;
|
||||
|
||||
delayedSample = inputSample;
|
||||
|
||||
|
@ -111,9 +111,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
{
|
||||
for (int sampleIndex = 0; sampleIndex < context.SampleCount; sampleIndex++)
|
||||
{
|
||||
float inputSample = *((float*)inputBuffers[channelIndex] + sampleIndex);
|
||||
float rawInputSample = *((float*)inputBuffers[channelIndex] + sampleIndex);
|
||||
|
||||
float sampleInputMax = Math.Abs(inputSample * Parameter.InputGain);
|
||||
float inputSample = (rawInputSample / short.MaxValue) * Parameter.InputGain;
|
||||
|
||||
float sampleInputMax = Math.Abs(inputSample);
|
||||
|
||||
float inputCoefficient = Parameter.ReleaseCoefficient;
|
||||
|
||||
@ -142,7 +144,9 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
ref float delayedSample = ref state.DelayedSampleBuffer[channelIndex * Parameter.DelayBufferSampleCountMax + state.DelayedSampleBufferPosition[channelIndex]];
|
||||
|
||||
*((float*)outputBuffers[channelIndex] + sampleIndex) = delayedSample * state.CompressionGain[channelIndex] * Parameter.OutputGain;
|
||||
float outputSample = delayedSample * state.CompressionGain[channelIndex] * Parameter.OutputGain;
|
||||
|
||||
*((float*)outputBuffers[channelIndex] + sampleIndex) = outputSample * short.MaxValue;
|
||||
|
||||
delayedSample = inputSample;
|
||||
|
||||
|
@ -76,7 +76,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
DataSourceHelper.WaveBufferInformation info = new DataSourceHelper.WaveBufferInformation
|
||||
{
|
||||
SourceSampleRate = SampleRate,
|
||||
SampleFormat = SampleFormat.PcmInt16,
|
||||
SampleFormat = SampleFormat.PcmFloat,
|
||||
Pitch = Pitch,
|
||||
DecodingBehaviour = DecodingBehaviour,
|
||||
ExtraParameter = 0,
|
||||
|
@ -600,19 +600,42 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void ResampleForUpsampler(Span<float> outputBuffer, ReadOnlySpan<float> inputBuffer, float ratio, ref float fraction, int sampleCount)
|
||||
{
|
||||
// TODO: use a bandwidth filter to have better resampling.
|
||||
// Currently a simple cubic interpolation, assuming duplicated values at edges.
|
||||
// TODO: Discover and use algorithm that the switch uses.
|
||||
|
||||
int inputBufferIndex = 0;
|
||||
int maxIndex = inputBuffer.Length - 1;
|
||||
int cubicEnd = inputBuffer.Length - 3;
|
||||
|
||||
for (int i = 0; i < sampleCount; i++)
|
||||
{
|
||||
float outputData = inputBuffer[inputBufferIndex];
|
||||
float s0, s1, s2, s3;
|
||||
|
||||
if (fraction > 1.0f)
|
||||
s1 = inputBuffer[inputBufferIndex];
|
||||
|
||||
if (inputBufferIndex == 0 || inputBufferIndex > cubicEnd)
|
||||
{
|
||||
outputData = inputBuffer[inputBufferIndex + 1];
|
||||
// Clamp interplation values at the ends of the input buffer.
|
||||
s0 = inputBuffer[Math.Max(0, inputBufferIndex - 1)];
|
||||
s2 = inputBuffer[Math.Min(maxIndex, inputBufferIndex + 1)];
|
||||
s3 = inputBuffer[Math.Min(maxIndex, inputBufferIndex + 2)];
|
||||
}
|
||||
else
|
||||
{
|
||||
s0 = inputBuffer[inputBufferIndex - 1];
|
||||
s2 = inputBuffer[inputBufferIndex + 1];
|
||||
s3 = inputBuffer[inputBufferIndex + 2];
|
||||
}
|
||||
|
||||
outputBuffer[i] = outputData;
|
||||
float a = s3 - s2 - s0 + s1;
|
||||
float b = s0 - s1 - a;
|
||||
float c = s2 - s0;
|
||||
float d = s1;
|
||||
|
||||
float f2 = fraction * fraction;
|
||||
float f3 = f2 * fraction;
|
||||
|
||||
outputBuffer[i] = a * f3 + b * f2 + c * fraction + d;
|
||||
|
||||
fraction += ratio;
|
||||
inputBufferIndex += (int)MathF.Truncate(fraction);
|
||||
|
@ -37,6 +37,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.State
|
||||
DectectorAverage.AsSpan().Fill(0.0f);
|
||||
CompressionGain.AsSpan().Fill(1.0f);
|
||||
DelayedSampleBufferPosition.AsSpan().Fill(0);
|
||||
DelayedSampleBuffer.AsSpan().Fill(0.0f);
|
||||
|
||||
UpdateParameter(ref parameter);
|
||||
}
|
||||
|
@ -558,7 +558,16 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
if (_rendererContext.BehaviourContext.IsEffectInfoVersion2Supported())
|
||||
{
|
||||
Memory<EffectResultState> dspResultState = _effectContext.GetDspStateMemory(effectId);
|
||||
Memory<EffectResultState> dspResultState;
|
||||
|
||||
if (effect.Parameter.StatisticsEnabled)
|
||||
{
|
||||
dspResultState = _effectContext.GetDspStateMemory(effectId);
|
||||
}
|
||||
else
|
||||
{
|
||||
dspResultState = Memory<EffectResultState>.Empty;
|
||||
}
|
||||
|
||||
_commandBuffer.GenerateLimiterEffectVersion2(bufferOffset, effect.Parameter, effect.State, dspResultState, effect.IsEnabled, workBuffer, nodeId);
|
||||
}
|
||||
|
@ -1,12 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Common
|
||||
{
|
||||
public static class EnumExtensions
|
||||
{
|
||||
public static T[] GetValues<T>()
|
||||
{
|
||||
return (T[])Enum.GetValues(typeof(T));
|
||||
}
|
||||
}
|
||||
}
|
@ -39,6 +39,7 @@ namespace Ryujinx.Common.Logging
|
||||
ServiceLm,
|
||||
ServiceMii,
|
||||
ServiceMm,
|
||||
ServiceMnpp,
|
||||
ServiceNfc,
|
||||
ServiceNfp,
|
||||
ServiceNgct,
|
||||
|
@ -9,6 +9,7 @@ namespace Ryujinx.Common.Logging
|
||||
Error,
|
||||
Guest,
|
||||
AccessLog,
|
||||
Notice
|
||||
Notice,
|
||||
Trace
|
||||
}
|
||||
}
|
||||
|
@ -90,11 +90,12 @@ namespace Ryujinx.Common.Logging
|
||||
public static Log? Guest { get; private set; }
|
||||
public static Log? AccessLog { get; private set; }
|
||||
public static Log? Stub { get; private set; }
|
||||
public static Log? Trace { get; private set; }
|
||||
public static Log Notice { get; } // Always enabled
|
||||
|
||||
static Logger()
|
||||
{
|
||||
m_EnabledClasses = new bool[Enum.GetNames(typeof(LogClass)).Length];
|
||||
m_EnabledClasses = new bool[Enum.GetNames<LogClass>().Length];
|
||||
|
||||
for (int index = 0; index < m_EnabledClasses.Length; index++)
|
||||
{
|
||||
@ -117,6 +118,7 @@ namespace Ryujinx.Common.Logging
|
||||
Error = new Log(LogLevel.Error);
|
||||
Warning = new Log(LogLevel.Warning);
|
||||
Info = new Log(LogLevel.Info);
|
||||
Trace = new Log(LogLevel.Trace);
|
||||
}
|
||||
|
||||
public static void RestartTime()
|
||||
@ -172,7 +174,7 @@ namespace Ryujinx.Common.Logging
|
||||
|
||||
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);
|
||||
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.AccessLog : AccessLog = enabled ? new Log(LogLevel.AccessLog): 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");
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ namespace Ryujinx.Common.Logging
|
||||
LogLevel.Error => ConsoleColor.Red,
|
||||
LogLevel.Stub => ConsoleColor.DarkGray,
|
||||
LogLevel.Notice => ConsoleColor.Cyan,
|
||||
LogLevel.Trace => ConsoleColor.DarkCyan,
|
||||
_ => ConsoleColor.Gray,
|
||||
};
|
||||
|
||||
|
@ -1,9 +1,10 @@
|
||||
using System;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Ryujinx.Common
|
||||
{
|
||||
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)
|
||||
{
|
||||
return (uint)AlignUp((int)value, size);
|
||||
@ -74,60 +75,7 @@ namespace Ryujinx.Common
|
||||
|
||||
public static int Pow2RoundDown(int value)
|
||||
{
|
||||
return IsPowerOfTwo32(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;
|
||||
return BitOperations.IsPow2(value) ? value : Pow2RoundUp(value) >> 1;
|
||||
}
|
||||
|
||||
public static long ReverseBits64(long value)
|
||||
|
@ -43,7 +43,7 @@ namespace Ryujinx.Common
|
||||
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,
|
||||
0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f,
|
||||
|
@ -20,7 +20,7 @@ namespace Ryujinx.Graphics.GAL
|
||||
|
||||
BufferHandle CreateBuffer(int size);
|
||||
|
||||
IProgram CreateProgram(IShader[] shaders);
|
||||
IProgram CreateProgram(IShader[] shaders, ShaderInfo info);
|
||||
|
||||
ISampler CreateSampler(SamplerCreateInfo info);
|
||||
ITexture CreateTexture(TextureCreateInfo info, float scale);
|
||||
@ -33,7 +33,7 @@ namespace Ryujinx.Graphics.GAL
|
||||
|
||||
Capabilities GetCapabilities();
|
||||
|
||||
IProgram LoadProgramBinary(byte[] programBinary);
|
||||
IProgram LoadProgramBinary(byte[] programBinary, bool hasFragmentShader, ShaderInfo info);
|
||||
|
||||
void SetBufferData(BufferHandle buffer, int offset, ReadOnlySpan<byte> data);
|
||||
|
||||
|
@ -5,17 +5,21 @@
|
||||
public ThreadedProgram Threaded { get; set; }
|
||||
|
||||
private byte[] _data;
|
||||
private bool _hasFragmentShader;
|
||||
private ShaderInfo _info;
|
||||
|
||||
public BinaryProgramRequest(ThreadedProgram program, byte[] data)
|
||||
public BinaryProgramRequest(ThreadedProgram program, byte[] data, bool hasFragmentShader, ShaderInfo info)
|
||||
{
|
||||
Threaded = program;
|
||||
|
||||
_data = data;
|
||||
_hasFragmentShader = hasFragmentShader;
|
||||
_info = info;
|
||||
}
|
||||
|
||||
public IProgram Create(IRenderer renderer)
|
||||
{
|
||||
return renderer.LoadProgramBinary(_data);
|
||||
return renderer.LoadProgramBinary(_data, _hasFragmentShader, _info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,12 +7,14 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources.Programs
|
||||
public ThreadedProgram Threaded { get; set; }
|
||||
|
||||
private IShader[] _shaders;
|
||||
private ShaderInfo _info;
|
||||
|
||||
public SourceProgramRequest(ThreadedProgram program, IShader[] shaders)
|
||||
public SourceProgramRequest(ThreadedProgram program, IShader[] shaders, ShaderInfo info)
|
||||
{
|
||||
Threaded = program;
|
||||
|
||||
_shaders = shaders;
|
||||
_info = info;
|
||||
}
|
||||
|
||||
public IProgram Create(IRenderer renderer)
|
||||
@ -24,7 +26,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources.Programs
|
||||
return threaded?.Base;
|
||||
}).ToArray();
|
||||
|
||||
return renderer.CreateProgram(shaders);
|
||||
return renderer.CreateProgram(shaders, _info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -268,10 +268,10 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
return handle;
|
||||
}
|
||||
|
||||
public IProgram CreateProgram(IShader[] shaders)
|
||||
public IProgram CreateProgram(IShader[] shaders, ShaderInfo info)
|
||||
{
|
||||
var program = new ThreadedProgram(this);
|
||||
SourceProgramRequest request = new SourceProgramRequest(program, shaders);
|
||||
SourceProgramRequest request = new SourceProgramRequest(program, shaders, info);
|
||||
Programs.Add(request);
|
||||
|
||||
New<CreateProgramCommand>().Set(Ref((IProgramRequest)request));
|
||||
@ -355,11 +355,11 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
_baseRenderer.Initialize(logLevel);
|
||||
}
|
||||
|
||||
public IProgram LoadProgramBinary(byte[] programBinary)
|
||||
public IProgram LoadProgramBinary(byte[] programBinary, bool hasFragmentShader, ShaderInfo info)
|
||||
{
|
||||
var program = new ThreadedProgram(this);
|
||||
|
||||
BinaryProgramRequest request = new BinaryProgramRequest(program, programBinary);
|
||||
BinaryProgramRequest request = new BinaryProgramRequest(program, programBinary, hasFragmentShader, info);
|
||||
Programs.Add(request);
|
||||
|
||||
New<CreateProgramCommand>().Set(Ref((IProgramRequest)request));
|
||||
|
12
Ryujinx.Graphics.GAL/ShaderInfo.cs
Normal file
12
Ryujinx.Graphics.GAL/ShaderInfo.cs
Normal file
@ -0,0 +1,12 @@
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public struct ShaderInfo
|
||||
{
|
||||
public int FragmentOutputMap { get; }
|
||||
|
||||
public ShaderInfo(int fragmentOutputMap)
|
||||
{
|
||||
FragmentOutputMap = fragmentOutputMap;
|
||||
}
|
||||
}
|
||||
}
|
@ -85,9 +85,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
||||
}
|
||||
|
||||
int alignWidth = Constants.StrideAlignment / bpp;
|
||||
return tex.RegionX == 0 &&
|
||||
tex.RegionY == 0 &&
|
||||
stride / bpp == BitUtils.AlignUp(xCount, alignWidth);
|
||||
return stride / bpp == BitUtils.AlignUp(xCount, alignWidth);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -161,6 +159,20 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
||||
var dst = Unsafe.As<uint, DmaTexture>(ref _state.State.SetDstBlockSize);
|
||||
var src = Unsafe.As<uint, DmaTexture>(ref _state.State.SetSrcBlockSize);
|
||||
|
||||
int srcRegionX = 0, srcRegionY = 0, dstRegionX = 0, dstRegionY = 0;
|
||||
|
||||
if (!srcLinear)
|
||||
{
|
||||
srcRegionX = src.RegionX;
|
||||
srcRegionY = src.RegionY;
|
||||
}
|
||||
|
||||
if (!dstLinear)
|
||||
{
|
||||
dstRegionX = dst.RegionX;
|
||||
dstRegionY = dst.RegionY;
|
||||
}
|
||||
|
||||
int srcStride = (int)_state.State.PitchIn;
|
||||
int dstStride = (int)_state.State.PitchOut;
|
||||
|
||||
@ -182,8 +194,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
||||
dst.MemoryLayout.UnpackGobBlocksInZ(),
|
||||
dstBpp);
|
||||
|
||||
(int srcBaseOffset, int srcSize) = srcCalculator.GetRectangleRange(src.RegionX, src.RegionY, xCount, yCount);
|
||||
(int dstBaseOffset, int dstSize) = dstCalculator.GetRectangleRange(dst.RegionX, dst.RegionY, xCount, yCount);
|
||||
(int srcBaseOffset, int srcSize) = srcCalculator.GetRectangleRange(srcRegionX, srcRegionY, xCount, yCount);
|
||||
(int dstBaseOffset, int dstSize) = dstCalculator.GetRectangleRange(dstRegionX, dstRegionY, xCount, yCount);
|
||||
|
||||
if (srcLinear && srcStride < 0)
|
||||
{
|
||||
@ -272,13 +284,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
||||
|
||||
for (int y = 0; y < yCount; y++)
|
||||
{
|
||||
srcCalculator.SetY(src.RegionY + y);
|
||||
dstCalculator.SetY(dst.RegionY + y);
|
||||
srcCalculator.SetY(srcRegionY + y);
|
||||
dstCalculator.SetY(dstRegionY + y);
|
||||
|
||||
for (int x = 0; x < xCount; x++)
|
||||
{
|
||||
int srcOffset = srcCalculator.GetOffset(src.RegionX + x);
|
||||
int dstOffset = dstCalculator.GetOffset(dst.RegionX + x);
|
||||
int srcOffset = srcCalculator.GetOffset(srcRegionX + x);
|
||||
int dstOffset = dstCalculator.GetOffset(dstRegionX + x);
|
||||
|
||||
*(T*)(dstBase + dstOffset) = *(T*)(srcBase + srcOffset);
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
||||
_ilGen.Emit(OpCodes.Ret);
|
||||
}
|
||||
|
||||
return (MacroExecute)_meth.CreateDelegate(typeof(MacroExecute));
|
||||
return _meth.CreateDelegate<MacroExecute>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -77,7 +77,8 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
|
||||
programInfo.Images.Count,
|
||||
programInfo.UsesInstanceId,
|
||||
programInfo.UsesRtLayer,
|
||||
programInfo.ClipDistancesWritten);
|
||||
programInfo.ClipDistancesWritten,
|
||||
programInfo.FragmentOutputMap);
|
||||
CBuffers = programInfo.CBuffers.ToArray();
|
||||
SBuffers = programInfo.SBuffers.ToArray();
|
||||
Textures = programInfo.Textures.ToArray();
|
||||
@ -97,7 +98,8 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
|
||||
Images,
|
||||
Header.UseFlags.HasFlag(UseFlags.InstanceId),
|
||||
Header.UseFlags.HasFlag(UseFlags.RtLayer),
|
||||
Header.ClipDistancesWritten);
|
||||
Header.ClipDistancesWritten,
|
||||
Header.FragmentOutputMap);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -26,7 +26,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
|
||||
/// <summary>
|
||||
/// Host shader entry header used for binding information.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x14)]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x18)]
|
||||
struct HostShaderCacheEntryHeader
|
||||
{
|
||||
/// <summary>
|
||||
@ -70,6 +70,11 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
|
||||
/// </summary>
|
||||
public byte Reserved;
|
||||
|
||||
/// <summary>
|
||||
/// Mask of components written by the fragment shader stage.
|
||||
/// </summary>
|
||||
public int FragmentOutputMap;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new host shader cache entry header.
|
||||
/// </summary>
|
||||
@ -78,6 +83,8 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
|
||||
/// <param name="texturesCount">Count of texture descriptors</param>
|
||||
/// <param name="imagesCount">Count of image descriptors</param>
|
||||
/// <param name="usesInstanceId">Set to true if the shader uses instance id</param>
|
||||
/// <param name="clipDistancesWritten">Mask of clip distances that are written to on the shader</param>
|
||||
/// <param name="fragmentOutputMap">Mask of components written by the fragment shader stage</param>
|
||||
public HostShaderCacheEntryHeader(
|
||||
int cBuffersCount,
|
||||
int sBuffersCount,
|
||||
@ -85,13 +92,15 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
|
||||
int imagesCount,
|
||||
bool usesInstanceId,
|
||||
bool usesRtLayer,
|
||||
byte clipDistancesWritten) : this()
|
||||
byte clipDistancesWritten,
|
||||
int fragmentOutputMap) : this()
|
||||
{
|
||||
CBuffersCount = cBuffersCount;
|
||||
SBuffersCount = sBuffersCount;
|
||||
TexturesCount = texturesCount;
|
||||
ImagesCount = imagesCount;
|
||||
ClipDistancesWritten = clipDistancesWritten;
|
||||
FragmentOutputMap = fragmentOutputMap;
|
||||
InUse = true;
|
||||
|
||||
UseFlags = usesInstanceId ? UseFlags.InstanceId : UseFlags.None;
|
||||
|
@ -40,7 +40,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// <summary>
|
||||
/// Version of the codegen (to be changed when codegen or guest format change).
|
||||
/// </summary>
|
||||
private const ulong ShaderCodeGenVersion = 3012;
|
||||
private const ulong ShaderCodeGenVersion = 3132;
|
||||
|
||||
// Progress reporting helpers
|
||||
private volatile int _shaderCount;
|
||||
@ -188,7 +188,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
{
|
||||
hostShaderEntries = HostShaderCacheEntry.Parse(hostProgramBinary, out ReadOnlySpan<byte> hostProgramBinarySpan);
|
||||
hostProgramBinary = hostProgramBinarySpan.ToArray();
|
||||
hostProgram = _context.Renderer.LoadProgramBinary(hostProgramBinary);
|
||||
hostProgram = _context.Renderer.LoadProgramBinary(hostProgramBinary, false, new ShaderInfo(-1));
|
||||
}
|
||||
|
||||
ShaderCompileTask task = new ShaderCompileTask(taskDoneEvent);
|
||||
@ -252,7 +252,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
|
||||
// Compile shader and create program as the shader program binary got invalidated.
|
||||
shader.HostShader = _context.Renderer.CompileShader(ShaderStage.Compute, program.Code);
|
||||
hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader });
|
||||
hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader }, new ShaderInfo(-1));
|
||||
|
||||
task.OnCompiled(hostProgram, (bool isNewProgramValid, ShaderCompileTask task) =>
|
||||
{
|
||||
@ -303,7 +303,18 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
{
|
||||
hostShaderEntries = HostShaderCacheEntry.Parse(hostProgramBinary, out ReadOnlySpan<byte> hostProgramBinarySpan);
|
||||
hostProgramBinary = hostProgramBinarySpan.ToArray();
|
||||
hostProgram = _context.Renderer.LoadProgramBinary(hostProgramBinary);
|
||||
|
||||
bool hasFragmentShader = false;
|
||||
int fragmentOutputMap = -1;
|
||||
int fragmentIndex = (int)ShaderStage.Fragment - 1;
|
||||
|
||||
if (hostShaderEntries[fragmentIndex] != null && hostShaderEntries[fragmentIndex].Header.InUse)
|
||||
{
|
||||
hasFragmentShader = true;
|
||||
fragmentOutputMap = hostShaderEntries[fragmentIndex].Header.FragmentOutputMap;
|
||||
}
|
||||
|
||||
hostProgram = _context.Renderer.LoadProgramBinary(hostProgramBinary, hasFragmentShader, new ShaderInfo(fragmentOutputMap));
|
||||
}
|
||||
|
||||
ShaderCompileTask task = new ShaderCompileTask(taskDoneEvent);
|
||||
@ -426,7 +437,15 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
hostShaders.Add(hostShader);
|
||||
}
|
||||
|
||||
hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray());
|
||||
int fragmentIndex = (int)ShaderStage.Fragment - 1;
|
||||
int fragmentOutputMap = -1;
|
||||
|
||||
if (shaders[fragmentIndex] != null)
|
||||
{
|
||||
fragmentOutputMap = shaders[fragmentIndex].Info.FragmentOutputMap;
|
||||
}
|
||||
|
||||
hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray(), new ShaderInfo(fragmentOutputMap));
|
||||
|
||||
task.OnCompiled(hostProgram, (bool isNewProgramValid, ShaderCompileTask task) =>
|
||||
{
|
||||
@ -617,7 +636,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
|
||||
shader.HostShader = _context.Renderer.CompileShader(ShaderStage.Compute, shader.Program.Code);
|
||||
|
||||
IProgram hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader });
|
||||
IProgram hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader }, new ShaderInfo(-1));
|
||||
|
||||
cpShader = new ShaderBundle(hostProgram, shader);
|
||||
|
||||
@ -755,7 +774,15 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
hostShaders.Add(hostShader);
|
||||
}
|
||||
|
||||
IProgram hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray());
|
||||
int fragmentIndex = (int)ShaderStage.Fragment - 1;
|
||||
int fragmentOutputMap = -1;
|
||||
|
||||
if (shaders[fragmentIndex] != null)
|
||||
{
|
||||
fragmentOutputMap = shaders[fragmentIndex].Info.FragmentOutputMap;
|
||||
}
|
||||
|
||||
IProgram hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray(), new ShaderInfo(fragmentOutputMap));
|
||||
|
||||
gpShaders = new ShaderBundle(hostProgram, shaders);
|
||||
|
||||
|
@ -118,7 +118,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.H264
|
||||
}
|
||||
|
||||
// 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,
|
||||
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
|
||||
};
|
||||
|
||||
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,
|
||||
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)
|
||||
{
|
||||
byte[] scan = list.Length == 16 ? ZigZagScan : ZigZagDirect;
|
||||
ReadOnlySpan<byte> scan = list.Length == 16 ? ZigZagScan : ZigZagDirect;
|
||||
|
||||
int lastScale = 8;
|
||||
|
||||
|
@ -15,7 +15,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
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.EightTap,
|
||||
|
@ -1,5 +1,6 @@
|
||||
using Ryujinx.Graphics.Nvdec.Vp9.Common;
|
||||
using Ryujinx.Graphics.Nvdec.Vp9.Types;
|
||||
using System;
|
||||
using static Ryujinx.Graphics.Nvdec.Vp9.Dsp.IntraPred;
|
||||
|
||||
namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
@ -24,7 +25,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
private const int NeedAbove = 1 << 2;
|
||||
private const int NeedAboveRight = 1 << 3;
|
||||
|
||||
private static readonly byte[] ExtendModes = new byte[]
|
||||
private static ReadOnlySpan<byte> ExtendModes => new byte[]
|
||||
{
|
||||
NeedAbove | NeedLeft, // DC
|
||||
NeedAbove, // V
|
||||
|
@ -10,7 +10,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
public short Row;
|
||||
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,
|
||||
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,
|
||||
|
@ -11,7 +11,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
|
||||
static FormatTable()
|
||||
{
|
||||
int tableSize = Enum.GetNames(typeof(Format)).Length;
|
||||
int tableSize = Enum.GetNames<Format>().Length;
|
||||
|
||||
Table = new FormatInfo[tableSize];
|
||||
TableImage = new SizedInternalFormat[tableSize];
|
||||
|
@ -53,7 +53,9 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
private ClipOrigin _clipOrigin;
|
||||
private ClipDepthMode _clipDepthMode;
|
||||
|
||||
private readonly uint[] _componentMasks;
|
||||
private uint _fragmentOutputMap;
|
||||
private uint _componentMasks;
|
||||
private uint _currentComponentMasks;
|
||||
|
||||
private uint _scissorEnables;
|
||||
|
||||
@ -73,12 +75,8 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
_clipOrigin = ClipOrigin.LowerLeft;
|
||||
_clipDepthMode = ClipDepthMode.NegativeOneToOne;
|
||||
|
||||
_componentMasks = new uint[Constants.MaxRenderTargets];
|
||||
|
||||
for (int index = 0; index < Constants.MaxRenderTargets; index++)
|
||||
{
|
||||
_componentMasks[index] = 0xf;
|
||||
}
|
||||
_fragmentOutputMap = uint.MaxValue;
|
||||
_componentMasks = uint.MaxValue;
|
||||
|
||||
var defaultScale = new Vector4<float> { X = 1f, Y = 0f, Z = 0f, W = 0f };
|
||||
new Span<Vector4<float>>(_renderScale).Fill(defaultScale);
|
||||
@ -1001,18 +999,30 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
|
||||
public void SetProgram(IProgram program)
|
||||
{
|
||||
_program = (Program)program;
|
||||
Program prg = (Program)program;
|
||||
|
||||
if (_tfEnabled)
|
||||
{
|
||||
GL.EndTransformFeedback();
|
||||
_program.Bind();
|
||||
prg.Bind();
|
||||
GL.BeginTransformFeedback(_tfTopology);
|
||||
}
|
||||
else
|
||||
{
|
||||
_program.Bind();
|
||||
prg.Bind();
|
||||
}
|
||||
|
||||
if (prg.HasFragmentShader && _fragmentOutputMap != (uint)prg.FragmentOutputMap)
|
||||
{
|
||||
_fragmentOutputMap = (uint)prg.FragmentOutputMap;
|
||||
|
||||
for (int index = 0; index < Constants.MaxRenderTargets; index++)
|
||||
{
|
||||
RestoreComponentMask(index, force: false);
|
||||
}
|
||||
}
|
||||
|
||||
_program = prg;
|
||||
}
|
||||
|
||||
public void SetRasterizerDiscard(bool discard)
|
||||
@ -1037,11 +1047,13 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
|
||||
public void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMasks)
|
||||
{
|
||||
_componentMasks = 0;
|
||||
|
||||
for (int index = 0; index < componentMasks.Length; index++)
|
||||
{
|
||||
_componentMasks[index] = componentMasks[index];
|
||||
_componentMasks |= componentMasks[index] << (index * 4);
|
||||
|
||||
RestoreComponentMask(index);
|
||||
RestoreComponentMask(index, force: false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1436,18 +1448,34 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
}
|
||||
}
|
||||
|
||||
public void RestoreComponentMask(int index)
|
||||
public void RestoreComponentMask(int index, bool force = true)
|
||||
{
|
||||
// If the bound render target is bgra, swap the red and blue masks.
|
||||
uint redMask = _fpIsBgra[index].X == 0 ? 1u : 4u;
|
||||
uint blueMask = _fpIsBgra[index].X == 0 ? 4u : 1u;
|
||||
|
||||
int shift = index * 4;
|
||||
uint componentMask = _componentMasks & _fragmentOutputMap;
|
||||
uint checkMask = 0xfu << shift;
|
||||
uint componentMaskAtIndex = componentMask & checkMask;
|
||||
|
||||
if (!force && componentMaskAtIndex == (_currentComponentMasks & checkMask))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
componentMask >>= shift;
|
||||
componentMask &= 0xfu;
|
||||
|
||||
GL.ColorMask(
|
||||
index,
|
||||
(_componentMasks[index] & redMask) != 0,
|
||||
(_componentMasks[index] & 2u) != 0,
|
||||
(_componentMasks[index] & blueMask) != 0,
|
||||
(_componentMasks[index] & 8u) != 0);
|
||||
(componentMask & redMask) != 0,
|
||||
(componentMask & 2u) != 0,
|
||||
(componentMask & blueMask) != 0,
|
||||
(componentMask & 8u) != 0);
|
||||
|
||||
_currentComponentMasks &= ~checkMask;
|
||||
_currentComponentMasks |= componentMaskAtIndex;
|
||||
}
|
||||
|
||||
public void RestoreScissor0Enable()
|
||||
|
@ -1,11 +1,8 @@
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Shader.CodeGen.Glsl;
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Ryujinx.Graphics.OpenGL
|
||||
{
|
||||
@ -29,7 +26,10 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
private ProgramLinkStatus _status = ProgramLinkStatus.Incomplete;
|
||||
private IShader[] _shaders;
|
||||
|
||||
public Program(IShader[] shaders)
|
||||
public bool HasFragmentShader;
|
||||
public int FragmentOutputMap { get; }
|
||||
|
||||
public Program(IShader[] shaders, int fragmentOutputMap)
|
||||
{
|
||||
Handle = GL.CreateProgram();
|
||||
|
||||
@ -37,17 +37,23 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
|
||||
for (int index = 0; index < shaders.Length; index++)
|
||||
{
|
||||
int shaderHandle = ((Shader)shaders[index]).Handle;
|
||||
Shader shader = (Shader)shaders[index];
|
||||
|
||||
GL.AttachShader(Handle, shaderHandle);
|
||||
if (shader.IsFragment)
|
||||
{
|
||||
HasFragmentShader = true;
|
||||
}
|
||||
|
||||
GL.AttachShader(Handle, shader.Handle);
|
||||
}
|
||||
|
||||
GL.LinkProgram(Handle);
|
||||
|
||||
_shaders = shaders;
|
||||
FragmentOutputMap = fragmentOutputMap;
|
||||
}
|
||||
|
||||
public Program(ReadOnlySpan<byte> code)
|
||||
public Program(ReadOnlySpan<byte> code, bool hasFragmentShader, int fragmentOutputMap)
|
||||
{
|
||||
BinaryFormat binaryFormat = (BinaryFormat)BinaryPrimitives.ReadInt32LittleEndian(code.Slice(code.Length - 4, 4));
|
||||
|
||||
@ -60,6 +66,9 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
GL.ProgramBinary(Handle, binaryFormat, (IntPtr)ptr, code.Length - 4);
|
||||
}
|
||||
}
|
||||
|
||||
HasFragmentShader = hasFragmentShader;
|
||||
FragmentOutputMap = fragmentOutputMap;
|
||||
}
|
||||
|
||||
public void Bind()
|
||||
|
@ -9,7 +9,7 @@ namespace Ryujinx.Graphics.OpenGL.Queries
|
||||
|
||||
public Counters()
|
||||
{
|
||||
int count = Enum.GetNames(typeof(CounterType)).Length;
|
||||
int count = Enum.GetNames<CounterType>().Length;
|
||||
|
||||
_counterQueues = new CounterQueue[count];
|
||||
}
|
||||
|
@ -66,9 +66,9 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
return Buffer.Create(size);
|
||||
}
|
||||
|
||||
public IProgram CreateProgram(IShader[] shaders)
|
||||
public IProgram CreateProgram(IShader[] shaders, ShaderInfo info)
|
||||
{
|
||||
return new Program(shaders);
|
||||
return new Program(shaders, info.FragmentOutputMap);
|
||||
}
|
||||
|
||||
public ISampler CreateSampler(SamplerCreateInfo info)
|
||||
@ -202,9 +202,9 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
_sync.Dispose();
|
||||
}
|
||||
|
||||
public IProgram LoadProgramBinary(byte[] programBinary)
|
||||
public IProgram LoadProgramBinary(byte[] programBinary, bool hasFragmentShader, ShaderInfo info)
|
||||
{
|
||||
return new Program(programBinary);
|
||||
return new Program(programBinary, hasFragmentShader, info.FragmentOutputMap);
|
||||
}
|
||||
|
||||
public void CreateSync(ulong id)
|
||||
|
@ -7,6 +7,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
class Shader : IShader
|
||||
{
|
||||
public int Handle { get; private set; }
|
||||
public bool IsFragment { get; }
|
||||
|
||||
public Shader(ShaderStage stage, string code)
|
||||
{
|
||||
@ -22,6 +23,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
};
|
||||
|
||||
Handle = GL.CreateShader(type);
|
||||
IsFragment = stage == ShaderStage.Fragment;
|
||||
|
||||
GL.ShaderSource(Handle, code);
|
||||
GL.CompileShader(Handle);
|
||||
|
@ -490,7 +490,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
}
|
||||
else
|
||||
{
|
||||
int usedAttributes = context.Config.UsedInputAttributes;
|
||||
int usedAttributes = context.Config.UsedInputAttributes | context.Config.PassthroughAttributes;
|
||||
while (usedAttributes != 0)
|
||||
{
|
||||
int index = BitOperations.TrailingZeroCount(usedAttributes);
|
||||
|
@ -5,32 +5,35 @@ namespace Ryujinx.Graphics.Shader
|
||||
{
|
||||
public class ShaderProgramInfo
|
||||
{
|
||||
public ReadOnlyCollection<BufferDescriptor> CBuffers { get; }
|
||||
public ReadOnlyCollection<BufferDescriptor> SBuffers { get; }
|
||||
public ReadOnlyCollection<BufferDescriptor> CBuffers { get; }
|
||||
public ReadOnlyCollection<BufferDescriptor> SBuffers { get; }
|
||||
public ReadOnlyCollection<TextureDescriptor> Textures { get; }
|
||||
public ReadOnlyCollection<TextureDescriptor> Images { get; }
|
||||
public ReadOnlyCollection<TextureDescriptor> Images { get; }
|
||||
|
||||
public bool UsesInstanceId { get; }
|
||||
public bool UsesRtLayer { get; }
|
||||
public byte ClipDistancesWritten { get; }
|
||||
public int FragmentOutputMap { get; }
|
||||
|
||||
public ShaderProgramInfo(
|
||||
BufferDescriptor[] cBuffers,
|
||||
BufferDescriptor[] sBuffers,
|
||||
BufferDescriptor[] cBuffers,
|
||||
BufferDescriptor[] sBuffers,
|
||||
TextureDescriptor[] textures,
|
||||
TextureDescriptor[] images,
|
||||
bool usesInstanceId,
|
||||
bool usesRtLayer,
|
||||
byte clipDistancesWritten)
|
||||
bool usesInstanceId,
|
||||
bool usesRtLayer,
|
||||
byte clipDistancesWritten,
|
||||
int fragmentOutputMap)
|
||||
{
|
||||
CBuffers = Array.AsReadOnly(cBuffers);
|
||||
SBuffers = Array.AsReadOnly(sBuffers);
|
||||
Textures = Array.AsReadOnly(textures);
|
||||
Images = Array.AsReadOnly(images);
|
||||
Images = Array.AsReadOnly(images);
|
||||
|
||||
UsesInstanceId = usesInstanceId;
|
||||
UsesRtLayer = usesRtLayer;
|
||||
ClipDistancesWritten = clipDistancesWritten;
|
||||
FragmentOutputMap = fragmentOutputMap;
|
||||
}
|
||||
}
|
||||
}
|
@ -172,11 +172,10 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
|
||||
for (int rtIndex = 0; rtIndex < 8; rtIndex++)
|
||||
{
|
||||
OmapTarget target = Config.OmapTargets[rtIndex];
|
||||
|
||||
for (int component = 0; component < 4; component++)
|
||||
{
|
||||
if (!target.ComponentEnabled(component))
|
||||
bool componentEnabled = (Config.OmapTargets & (1 << (rtIndex * 4 + component))) != 0;
|
||||
if (!componentEnabled)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -210,7 +209,8 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
}
|
||||
}
|
||||
|
||||
if (target.Enabled)
|
||||
bool targetEnabled = (Config.OmapTargets & (0xf << (rtIndex * 4))) != 0;
|
||||
if (targetEnabled)
|
||||
{
|
||||
Config.SetOutputUserAttribute(rtIndex, perPatch: false);
|
||||
regIndexBase += 4;
|
||||
|
@ -25,9 +25,9 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
|
||||
public ImapPixelType[] ImapTypes { get; }
|
||||
|
||||
public OmapTarget[] OmapTargets { get; }
|
||||
public bool OmapSampleMask { get; }
|
||||
public bool OmapDepth { get; }
|
||||
public int OmapTargets { get; }
|
||||
public bool OmapSampleMask { get; }
|
||||
public bool OmapDepth { get; }
|
||||
|
||||
public IGpuAccessor GpuAccessor { get; }
|
||||
|
||||
@ -135,21 +135,8 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
|
||||
public int GetDepthRegister()
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for (int index = 0; index < OmapTargets.Length; index++)
|
||||
{
|
||||
for (int component = 0; component < 4; component++)
|
||||
{
|
||||
if (OmapTargets[index].ComponentEnabled(component))
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The depth register is always two registers after the last color output.
|
||||
return count + 1;
|
||||
return BitOperations.PopCount((uint)OmapTargets) + 1;
|
||||
}
|
||||
|
||||
public TextureFormat GetTextureFormat(int handle, int cbufSlot = -1)
|
||||
@ -382,7 +369,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
inst &= Instruction.Mask;
|
||||
bool isImage = inst == Instruction.ImageLoad || 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);
|
||||
|
||||
if (isImage)
|
||||
|
@ -36,37 +36,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
}
|
||||
}
|
||||
|
||||
struct OmapTarget
|
||||
{
|
||||
public bool Red { get; }
|
||||
public bool Green { get; }
|
||||
public bool Blue { get; }
|
||||
public bool Alpha { get; }
|
||||
|
||||
public bool Enabled => Red || Green || Blue || Alpha;
|
||||
|
||||
public OmapTarget(bool red, bool green, bool blue, bool alpha)
|
||||
{
|
||||
Red = red;
|
||||
Green = green;
|
||||
Blue = blue;
|
||||
Alpha = alpha;
|
||||
}
|
||||
|
||||
public bool ComponentEnabled(int component)
|
||||
{
|
||||
switch (component)
|
||||
{
|
||||
case 0: return Red;
|
||||
case 1: return Green;
|
||||
case 2: return Blue;
|
||||
case 3: return Alpha;
|
||||
}
|
||||
|
||||
throw new ArgumentOutOfRangeException(nameof(component));
|
||||
}
|
||||
}
|
||||
|
||||
class ShaderHeader
|
||||
{
|
||||
public int SphType { get; }
|
||||
@ -85,7 +54,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
public bool GpPassthrough { get; }
|
||||
|
||||
public bool DoesLoadOrStore { get; }
|
||||
public bool DoesFp64 { get; }
|
||||
public bool DoesFp64 { get; }
|
||||
|
||||
public int StreamOutMask { get; }
|
||||
|
||||
@ -104,13 +73,13 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
public int MaxOutputVertexCount { get; }
|
||||
|
||||
public int StoreReqStart { get; }
|
||||
public int StoreReqEnd { get; }
|
||||
public int StoreReqEnd { get; }
|
||||
|
||||
public ImapPixelType[] ImapTypes { get; }
|
||||
|
||||
public OmapTarget[] OmapTargets { get; }
|
||||
public bool OmapSampleMask { get; }
|
||||
public bool OmapDepth { get; }
|
||||
public int OmapTargets { get; }
|
||||
public bool OmapSampleMask { get; }
|
||||
public bool OmapDepth { get; }
|
||||
|
||||
public ShaderHeader(IGpuAccessor gpuAccessor, ulong address)
|
||||
{
|
||||
@ -144,7 +113,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
GpPassthrough = commonWord0.Extract(24);
|
||||
|
||||
DoesLoadOrStore = commonWord0.Extract(26);
|
||||
DoesFp64 = commonWord0.Extract(27);
|
||||
DoesFp64 = commonWord0.Extract(27);
|
||||
|
||||
StreamOutMask = commonWord0.Extract(28, 4);
|
||||
|
||||
@ -163,7 +132,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
MaxOutputVertexCount = commonWord4.Extract(0, 12);
|
||||
|
||||
StoreReqStart = commonWord4.Extract(12, 8);
|
||||
StoreReqEnd = commonWord4.Extract(24, 8);
|
||||
StoreReqEnd = commonWord4.Extract(24, 8);
|
||||
|
||||
ImapTypes = new ImapPixelType[32];
|
||||
|
||||
@ -179,21 +148,11 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
}
|
||||
|
||||
int type2OmapTarget = header[18];
|
||||
int type2Omap = header[19];
|
||||
|
||||
OmapTargets = new OmapTarget[8];
|
||||
|
||||
for (int offset = 0; offset < OmapTargets.Length * 4; offset += 4)
|
||||
{
|
||||
OmapTargets[offset >> 2] = new OmapTarget(
|
||||
type2OmapTarget.Extract(offset + 0),
|
||||
type2OmapTarget.Extract(offset + 1),
|
||||
type2OmapTarget.Extract(offset + 2),
|
||||
type2OmapTarget.Extract(offset + 3));
|
||||
}
|
||||
int type2Omap = header[19];
|
||||
|
||||
OmapTargets = type2OmapTarget;
|
||||
OmapSampleMask = type2Omap.Extract(0);
|
||||
OmapDepth = type2Omap.Extract(1);
|
||||
OmapDepth = type2Omap.Extract(1);
|
||||
}
|
||||
}
|
||||
}
|
@ -105,7 +105,8 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
config.GetImageDescriptors(),
|
||||
config.UsedFeatures.HasFlag(FeatureFlags.InstanceId),
|
||||
config.UsedFeatures.HasFlag(FeatureFlags.RtLayer),
|
||||
config.ClipDistancesWritten);
|
||||
config.ClipDistancesWritten,
|
||||
config.OmapTargets);
|
||||
|
||||
return program;
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Ryujinx.Common;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
using static Ryujinx.Graphics.Texture.BlockLinearConstants;
|
||||
@ -47,15 +48,15 @@ namespace Ryujinx.Graphics.Texture
|
||||
{
|
||||
_texBpp = bpp;
|
||||
|
||||
_bppShift = BitUtils.CountTrailingZeros32(bpp);
|
||||
_bppShift = BitOperations.TrailingZeroCount(bpp);
|
||||
|
||||
_bhMask = gobBlocksInY - 1;
|
||||
_bdMask = gobBlocksInZ - 1;
|
||||
|
||||
_bhShift = BitUtils.CountTrailingZeros32(gobBlocksInY);
|
||||
_bdShift = BitUtils.CountTrailingZeros32(gobBlocksInZ);
|
||||
_bhShift = BitOperations.TrailingZeroCount(gobBlocksInY);
|
||||
_bdShift = BitOperations.TrailingZeroCount(gobBlocksInZ);
|
||||
|
||||
_xShift = BitUtils.CountTrailingZeros32(GobSize * gobBlocksInY * gobBlocksInZ);
|
||||
_xShift = BitOperations.TrailingZeroCount(GobSize * gobBlocksInY * gobBlocksInZ);
|
||||
|
||||
RobAndSliceSizes rsSizes = GetRobAndSliceSizes(width, height, gobBlocksInY, gobBlocksInZ);
|
||||
|
||||
|
@ -102,7 +102,7 @@ namespace Ryujinx.HLE.FileSystem.Content
|
||||
_contentDictionary = new SortedDictionary<(ulong, NcaContentType), string>();
|
||||
_locationEntries = new Dictionary<StorageId, LinkedList<LocationEntry>>();
|
||||
|
||||
foreach (StorageId storageId in Enum.GetValues(typeof(StorageId)))
|
||||
foreach (StorageId storageId in Enum.GetValues<StorageId>())
|
||||
{
|
||||
string contentDirectory = null;
|
||||
string contentPathString = null;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user