Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
619ac86bd0 | ||
|
7a1ab71c73 | ||
|
dc4ba3993b | ||
|
81f1a4dc31 | ||
|
c64524a240 |
@@ -251,6 +251,13 @@ namespace ARMeilleure.Decoders
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Compare and branch instructions are always conditional.
|
||||||
|
if (opCode.Instruction.Name == InstName.Cbz ||
|
||||||
|
opCode.Instruction.Name == InstName.Cbnz)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Note: On ARM32, most instructions have conditional execution,
|
// Note: On ARM32, most instructions have conditional execution,
|
||||||
// so there's no "Always" (unconditional) branch like on ARM64.
|
// so there's no "Always" (unconditional) branch like on ARM64.
|
||||||
// We need to check if the condition is "Always" instead.
|
// We need to check if the condition is "Always" instead.
|
||||||
|
@@ -3,6 +3,7 @@ namespace ARMeilleure.Decoders
|
|||||||
interface IOpCode32Mem : IOpCode32
|
interface IOpCode32Mem : IOpCode32
|
||||||
{
|
{
|
||||||
int Rt { get; }
|
int Rt { get; }
|
||||||
|
int Rt2 => Rt | 1;
|
||||||
int Rn { get; }
|
int Rn { get; }
|
||||||
|
|
||||||
bool WBack { get; }
|
bool WBack { get; }
|
||||||
|
@@ -4,7 +4,6 @@ namespace ARMeilleure.Decoders
|
|||||||
{
|
{
|
||||||
public int Rd { get; }
|
public int Rd { get; }
|
||||||
|
|
||||||
public bool Add => true;
|
|
||||||
public int Immediate { get; }
|
public int Immediate { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16Adr(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16Adr(inst, address, opCode);
|
||||||
|
16
ARMeilleure/Decoders/OpCodeT32AluImm12.cs
Normal file
16
ARMeilleure/Decoders/OpCodeT32AluImm12.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT32AluImm12 : OpCodeT32Alu, IOpCode32AluImm
|
||||||
|
{
|
||||||
|
public int Immediate { get; }
|
||||||
|
|
||||||
|
public bool IsRotated => false;
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32AluImm12(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT32AluImm12(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Immediate = (opCode & 0xff) | ((opCode >> 4) & 0x700) | ((opCode >> 15) & 0x800);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
ARMeilleure/Decoders/OpCodeT32AluReg.cs
Normal file
14
ARMeilleure/Decoders/OpCodeT32AluReg.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT32AluReg : OpCodeT32Alu, IOpCode32AluReg
|
||||||
|
{
|
||||||
|
public int Rm { get; }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32AluReg(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT32AluReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rm = (opCode >> 0) & 0xf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -23,7 +23,7 @@ namespace ARMeilleure.Decoders
|
|||||||
Add = ((opCode >> 23) & 1) != 0;
|
Add = ((opCode >> 23) & 1) != 0;
|
||||||
WBack = ((opCode >> 21) & 1) != 0;
|
WBack = ((opCode >> 21) & 1) != 0;
|
||||||
|
|
||||||
Immediate = opCode & 0xff;
|
Immediate = (opCode & 0xff) << 2;
|
||||||
|
|
||||||
IsLoad = ((opCode >> 20) & 1) != 0;
|
IsLoad = ((opCode >> 20) & 1) != 0;
|
||||||
}
|
}
|
||||||
|
19
ARMeilleure/Decoders/OpCodeT32MovImm16.cs
Normal file
19
ARMeilleure/Decoders/OpCodeT32MovImm16.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using ARMeilleure.Common;
|
||||||
|
using System.Runtime.Intrinsics;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT32MovImm16 : OpCodeT32Alu, IOpCode32AluImm
|
||||||
|
{
|
||||||
|
public int Immediate { get; }
|
||||||
|
|
||||||
|
public bool IsRotated => false;
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32MovImm16(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT32MovImm16(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Immediate = (opCode & 0xff) | ((opCode >> 4) & 0x700) | ((opCode >> 15) & 0x800) | ((opCode >> 4) & 0xf000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
ARMeilleure/Decoders/OpCodeT32ShiftReg.cs
Normal file
19
ARMeilleure/Decoders/OpCodeT32ShiftReg.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT32ShiftReg : OpCodeT32Alu, IOpCode32AluRsReg
|
||||||
|
{
|
||||||
|
public int Rm => Rn;
|
||||||
|
public int Rs { get; }
|
||||||
|
|
||||||
|
public ShiftType ShiftType { get; }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32ShiftReg(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT32ShiftReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rs = (opCode >> 0) & 0xf;
|
||||||
|
|
||||||
|
ShiftType = (ShiftType)((opCode >> 21) & 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
ARMeilleure/Decoders/OpCodeT32Tb.cs
Normal file
16
ARMeilleure/Decoders/OpCodeT32Tb.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT32Tb : OpCodeT32, IOpCode32BReg
|
||||||
|
{
|
||||||
|
public int Rm { get; }
|
||||||
|
public int Rn { get; }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32Tb(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT32Tb(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rm = (opCode >> 0) & 0xf;
|
||||||
|
Rn = (opCode >> 16) & 0xf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1021,7 +1021,7 @@ namespace ARMeilleure.Decoders
|
|||||||
SetT16("01000101xxxxxxxx", InstName.Cmp, InstEmit32.Cmp, OpCodeT16AluRegHigh.Create);
|
SetT16("01000101xxxxxxxx", InstName.Cmp, InstEmit32.Cmp, OpCodeT16AluRegHigh.Create);
|
||||||
SetT16("01000110xxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16AluRegHigh.Create);
|
SetT16("01000110xxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16AluRegHigh.Create);
|
||||||
SetT16("010001110xxxx000", InstName.Bx, InstEmit32.Bx, OpCodeT16BReg.Create);
|
SetT16("010001110xxxx000", InstName.Bx, InstEmit32.Bx, OpCodeT16BReg.Create);
|
||||||
SetT16("010001111xxxx000", InstName.Blx, InstEmit32.Blx, OpCodeT16BReg.Create);
|
SetT16("010001111xxxx000", InstName.Blx, InstEmit32.Blxr, OpCodeT16BReg.Create);
|
||||||
SetT16("01001xxxxxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT16MemLit.Create);
|
SetT16("01001xxxxxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT16MemLit.Create);
|
||||||
SetT16("0101000xxxxxxxxx", InstName.Str, InstEmit32.Str, OpCodeT16MemReg.Create);
|
SetT16("0101000xxxxxxxxx", InstName.Str, InstEmit32.Str, OpCodeT16MemReg.Create);
|
||||||
SetT16("0101001xxxxxxxxx", InstName.Strh, InstEmit32.Strh, OpCodeT16MemReg.Create);
|
SetT16("0101001xxxxxxxxx", InstName.Strh, InstEmit32.Strh, OpCodeT16MemReg.Create);
|
||||||
@@ -1069,6 +1069,7 @@ namespace ARMeilleure.Decoders
|
|||||||
SetT32("11110x01010xxxxx0xxxxxxxxxxxxxxx", InstName.Adc, InstEmit32.Adc, OpCodeT32AluImm.Create);
|
SetT32("11110x01010xxxxx0xxxxxxxxxxxxxxx", InstName.Adc, InstEmit32.Adc, OpCodeT32AluImm.Create);
|
||||||
SetT32("11101011000<xxxx0xxx<<<<xxxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT32AluRsImm.Create);
|
SetT32("11101011000<xxxx0xxx<<<<xxxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT32AluRsImm.Create);
|
||||||
SetT32("11110x01000<xxxx0xxx<<<<xxxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT32AluImm.Create);
|
SetT32("11110x01000<xxxx0xxx<<<<xxxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT32AluImm.Create);
|
||||||
|
SetT32("11110x100000xxxx0xxxxxxxxxxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT32AluImm12.Create);
|
||||||
SetT32("11101010000<xxxx0xxx<<<<xxxxxxxx", InstName.And, InstEmit32.And, OpCodeT32AluRsImm.Create);
|
SetT32("11101010000<xxxx0xxx<<<<xxxxxxxx", InstName.And, InstEmit32.And, OpCodeT32AluRsImm.Create);
|
||||||
SetT32("11110x00000<xxxx0xxx<<<<xxxxxxxx", InstName.And, InstEmit32.And, OpCodeT32AluImm.Create);
|
SetT32("11110x00000<xxxx0xxx<<<<xxxxxxxx", InstName.And, InstEmit32.And, OpCodeT32AluImm.Create);
|
||||||
SetT32("11110x<<<xxxxxxx10x0xxxxxxxxxxxx", InstName.B, InstEmit32.B, OpCodeT32BImm20.Create);
|
SetT32("11110x<<<xxxxxxx10x0xxxxxxxxxxxx", InstName.B, InstEmit32.B, OpCodeT32BImm20.Create);
|
||||||
@@ -1077,12 +1078,14 @@ namespace ARMeilleure.Decoders
|
|||||||
SetT32("11110x00001xxxxx0xxxxxxxxxxxxxxx", InstName.Bic, InstEmit32.Bic, OpCodeT32AluImm.Create);
|
SetT32("11110x00001xxxxx0xxxxxxxxxxxxxxx", InstName.Bic, InstEmit32.Bic, OpCodeT32AluImm.Create);
|
||||||
SetT32("11110xxxxxxxxxxx11x1xxxxxxxxxxxx", InstName.Bl, InstEmit32.Bl, OpCodeT32BImm24.Create);
|
SetT32("11110xxxxxxxxxxx11x1xxxxxxxxxxxx", InstName.Bl, InstEmit32.Bl, OpCodeT32BImm24.Create);
|
||||||
SetT32("11110xxxxxxxxxxx11x0xxxxxxxxxxx0", InstName.Blx, InstEmit32.Blx, OpCodeT32BImm24.Create);
|
SetT32("11110xxxxxxxxxxx11x0xxxxxxxxxxx0", InstName.Blx, InstEmit32.Blx, OpCodeT32BImm24.Create);
|
||||||
|
SetT32("111110101011xxxx1111xxxx1000xxxx", InstName.Clz, InstEmit32.Clz, OpCodeT32AluReg.Create);
|
||||||
SetT32("111010110001xxxx0xxx1111xxxxxxxx", InstName.Cmn, InstEmit32.Cmn, OpCodeT32AluRsImm.Create);
|
SetT32("111010110001xxxx0xxx1111xxxxxxxx", InstName.Cmn, InstEmit32.Cmn, OpCodeT32AluRsImm.Create);
|
||||||
SetT32("11110x010001xxxx0xxx1111xxxxxxxx", InstName.Cmn, InstEmit32.Cmn, OpCodeT32AluImm.Create);
|
SetT32("11110x010001xxxx0xxx1111xxxxxxxx", InstName.Cmn, InstEmit32.Cmn, OpCodeT32AluImm.Create);
|
||||||
SetT32("111010111011xxxx0xxx1111xxxxxxxx", InstName.Cmp, InstEmit32.Cmp, OpCodeT32AluRsImm.Create);
|
SetT32("111010111011xxxx0xxx1111xxxxxxxx", InstName.Cmp, InstEmit32.Cmp, OpCodeT32AluRsImm.Create);
|
||||||
SetT32("11110x011011xxxx0xxx1111xxxxxxxx", InstName.Cmp, InstEmit32.Cmp, OpCodeT32AluImm.Create);
|
SetT32("11110x011011xxxx0xxx1111xxxxxxxx", InstName.Cmp, InstEmit32.Cmp, OpCodeT32AluImm.Create);
|
||||||
SetT32("11101010100<xxxx0xxx<<<<xxxxxxxx", InstName.Eor, InstEmit32.Eor, OpCodeT32AluRsImm.Create);
|
SetT32("11101010100<xxxx0xxx<<<<xxxxxxxx", InstName.Eor, InstEmit32.Eor, OpCodeT32AluRsImm.Create);
|
||||||
SetT32("11110x00100<xxxx0xxx<<<<xxxxxxxx", InstName.Eor, InstEmit32.Eor, OpCodeT32AluImm.Create);
|
SetT32("11110x00100<xxxx0xxx<<<<xxxxxxxx", InstName.Eor, InstEmit32.Eor, OpCodeT32AluImm.Create);
|
||||||
|
SetT32("111010001101xxxxxxxx111110101111", InstName.Lda, InstEmit32.Lda, OpCodeT32MemLdEx.Create);
|
||||||
SetT32("111010001101xxxxxxxx111111101111", InstName.Ldaex, InstEmit32.Ldaex, OpCodeT32MemLdEx.Create);
|
SetT32("111010001101xxxxxxxx111111101111", InstName.Ldaex, InstEmit32.Ldaex, OpCodeT32MemLdEx.Create);
|
||||||
SetT32("1110100010x1xxxxxxxxxxxxxxxxxxxx", InstName.Ldm, InstEmit32.Ldm, OpCodeT32MemMult.Create);
|
SetT32("1110100010x1xxxxxxxxxxxxxxxxxxxx", InstName.Ldm, InstEmit32.Ldm, OpCodeT32MemMult.Create);
|
||||||
SetT32("1110100100x1xxxxxxxxxxxxxxxxxxxx", InstName.Ldm, InstEmit32.Ldm, OpCodeT32MemMult.Create);
|
SetT32("1110100100x1xxxxxxxxxxxxxxxxxxxx", InstName.Ldm, InstEmit32.Ldm, OpCodeT32MemMult.Create);
|
||||||
@@ -1095,7 +1098,8 @@ namespace ARMeilleure.Decoders
|
|||||||
SetT32("111110000001xxxx<<<<1100xxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT32MemImm8.Create);
|
SetT32("111110000001xxxx<<<<1100xxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT32MemImm8.Create);
|
||||||
SetT32("111110000001xxxx<<<<11x1xxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT32MemImm8.Create);
|
SetT32("111110000001xxxx<<<<11x1xxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT32MemImm8.Create);
|
||||||
SetT32("111110001001xxxxxxxxxxxxxxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT32MemImm12.Create);
|
SetT32("111110001001xxxxxxxxxxxxxxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT32MemImm12.Create);
|
||||||
SetT32("1110100>x1>1<<<<xxxxxxxxxxxxxxxx", InstName.Ldrd, InstEmit32.Ldrd, OpCodeT32MemImm8D.Create);
|
SetT32("11101000x111<<<<xxxxxxxxxxxxxxxx", InstName.Ldrd, InstEmit32.Ldrd, OpCodeT32MemImm8D.Create);
|
||||||
|
SetT32("11101001x1x1<<<<xxxxxxxxxxxxxxxx", InstName.Ldrd, InstEmit32.Ldrd, OpCodeT32MemImm8D.Create);
|
||||||
SetT32("111110000011xxxx<<<<10x1xxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT32MemImm8.Create);
|
SetT32("111110000011xxxx<<<<10x1xxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT32MemImm8.Create);
|
||||||
SetT32("111110000011xxxx<<<<1100xxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT32MemImm8.Create);
|
SetT32("111110000011xxxx<<<<1100xxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT32MemImm8.Create);
|
||||||
SetT32("111110000011xxxx<<<<11x1xxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT32MemImm8.Create);
|
SetT32("111110000011xxxx<<<<11x1xxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT32MemImm8.Create);
|
||||||
@@ -1109,9 +1113,12 @@ namespace ARMeilleure.Decoders
|
|||||||
SetT32("111110010011xxxx<<<<11x1xxxxxxxx", InstName.Ldrsh, InstEmit32.Ldrsh, OpCodeT32MemImm8.Create);
|
SetT32("111110010011xxxx<<<<11x1xxxxxxxx", InstName.Ldrsh, InstEmit32.Ldrsh, OpCodeT32MemImm8.Create);
|
||||||
SetT32("111110011011xxxxxxxxxxxxxxxxxxxx", InstName.Ldrsh, InstEmit32.Ldrsh, OpCodeT32MemImm12.Create);
|
SetT32("111110011011xxxxxxxxxxxxxxxxxxxx", InstName.Ldrsh, InstEmit32.Ldrsh, OpCodeT32MemImm12.Create);
|
||||||
SetT32("11101010010x11110xxxxxxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT32AluRsImm.Create);
|
SetT32("11101010010x11110xxxxxxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT32AluRsImm.Create);
|
||||||
|
SetT32("111110100xxxxxxx1111xxxx0000xxxx", InstName.Mov, InstEmit32.Mov, OpCodeT32ShiftReg.Create);
|
||||||
SetT32("11110x00010x11110xxxxxxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT32AluImm.Create);
|
SetT32("11110x00010x11110xxxxxxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT32AluImm.Create);
|
||||||
|
SetT32("11110x100100xxxx0xxxxxxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT32MovImm16.Create);
|
||||||
SetT32("11101010011x11110xxxxxxxxxxxxxxx", InstName.Mvn, InstEmit32.Mvn, OpCodeT32AluRsImm.Create);
|
SetT32("11101010011x11110xxxxxxxxxxxxxxx", InstName.Mvn, InstEmit32.Mvn, OpCodeT32AluRsImm.Create);
|
||||||
SetT32("11110x00011x11110xxxxxxxxxxxxxxx", InstName.Mvn, InstEmit32.Mvn, OpCodeT32AluImm.Create);
|
SetT32("11110x00011x11110xxxxxxxxxxxxxxx", InstName.Mvn, InstEmit32.Mvn, OpCodeT32AluImm.Create);
|
||||||
|
SetT32("11110011101011111000000000000000", InstName.Nop, InstEmit32.Nop, OpCodeT32.Create);
|
||||||
SetT32("11101010011x<<<<0xxxxxxxxxxxxxxx", InstName.Orn, InstEmit32.Orn, OpCodeT32AluRsImm.Create);
|
SetT32("11101010011x<<<<0xxxxxxxxxxxxxxx", InstName.Orn, InstEmit32.Orn, OpCodeT32AluRsImm.Create);
|
||||||
SetT32("11110x00011x<<<<0xxxxxxxxxxxxxxx", InstName.Orn, InstEmit32.Orn, OpCodeT32AluImm.Create);
|
SetT32("11110x00011x<<<<0xxxxxxxxxxxxxxx", InstName.Orn, InstEmit32.Orn, OpCodeT32AluImm.Create);
|
||||||
SetT32("11101010010x<<<<0xxxxxxxxxxxxxxx", InstName.Orr, InstEmit32.Orr, OpCodeT32AluRsImm.Create);
|
SetT32("11101010010x<<<<0xxxxxxxxxxxxxxx", InstName.Orr, InstEmit32.Orr, OpCodeT32AluRsImm.Create);
|
||||||
@@ -1128,11 +1135,14 @@ namespace ARMeilleure.Decoders
|
|||||||
SetT32("111110000100<<<<xxxx000000xxxxxx", InstName.Str, InstEmit32.Str, OpCodeT32MemRsImm.Create);
|
SetT32("111110000100<<<<xxxx000000xxxxxx", InstName.Str, InstEmit32.Str, OpCodeT32MemRsImm.Create);
|
||||||
SetT32("111110000000xxxxxxxx1<<>xxxxxxxx", InstName.Strb, InstEmit32.Strb, OpCodeT32MemImm8.Create);
|
SetT32("111110000000xxxxxxxx1<<>xxxxxxxx", InstName.Strb, InstEmit32.Strb, OpCodeT32MemImm8.Create);
|
||||||
SetT32("111110001000xxxxxxxxxxxxxxxxxxxx", InstName.Strb, InstEmit32.Strb, OpCodeT32MemImm12.Create);
|
SetT32("111110001000xxxxxxxxxxxxxxxxxxxx", InstName.Strb, InstEmit32.Strb, OpCodeT32MemImm12.Create);
|
||||||
SetT32("1110100>x1>0<<<<xxxxxxxxxxxxxxxx", InstName.Strd, InstEmit32.Strd, OpCodeT32MemImm8D.Create);
|
SetT32("11101000x110<<<<xxxxxxxxxxxxxxxx", InstName.Strd, InstEmit32.Strd, OpCodeT32MemImm8D.Create);
|
||||||
|
SetT32("11101001x1x0<<<<xxxxxxxxxxxxxxxx", InstName.Strd, InstEmit32.Strd, OpCodeT32MemImm8D.Create);
|
||||||
SetT32("111110000010xxxxxxxx1<<>xxxxxxxx", InstName.Strh, InstEmit32.Strh, OpCodeT32MemImm8.Create);
|
SetT32("111110000010xxxxxxxx1<<>xxxxxxxx", InstName.Strh, InstEmit32.Strh, OpCodeT32MemImm8.Create);
|
||||||
SetT32("111110001010xxxxxxxxxxxxxxxxxxxx", InstName.Strh, InstEmit32.Strh, OpCodeT32MemImm12.Create);
|
SetT32("111110001010xxxxxxxxxxxxxxxxxxxx", InstName.Strh, InstEmit32.Strh, OpCodeT32MemImm12.Create);
|
||||||
SetT32("11101011101<xxxx0xxx<<<<xxxxxxxx", InstName.Sub, InstEmit32.Sub, OpCodeT32AluRsImm.Create);
|
SetT32("11101011101<xxxx0xxx<<<<xxxxxxxx", InstName.Sub, InstEmit32.Sub, OpCodeT32AluRsImm.Create);
|
||||||
SetT32("11110x01101<xxxx0xxx<<<<xxxxxxxx", InstName.Sub, InstEmit32.Sub, OpCodeT32AluImm.Create);
|
SetT32("11110x01101<xxxx0xxx<<<<xxxxxxxx", InstName.Sub, InstEmit32.Sub, OpCodeT32AluImm.Create);
|
||||||
|
SetT32("111010001101xxxx111100000000xxxx", InstName.Tbb, InstEmit32.Tbb, OpCodeT32Tb.Create);
|
||||||
|
SetT32("111010001101xxxx111100000001xxxx", InstName.Tbh, InstEmit32.Tbh, OpCodeT32Tb.Create);
|
||||||
SetT32("111010101001xxxx0xxx1111xxxxxxxx", InstName.Teq, InstEmit32.Teq, OpCodeT32AluRsImm.Create);
|
SetT32("111010101001xxxx0xxx1111xxxxxxxx", InstName.Teq, InstEmit32.Teq, OpCodeT32AluRsImm.Create);
|
||||||
SetT32("11110x001001xxxx0xxx1111xxxxxxxx", InstName.Teq, InstEmit32.Teq, OpCodeT32AluImm.Create);
|
SetT32("11110x001001xxxx0xxx1111xxxxxxxx", InstName.Teq, InstEmit32.Teq, OpCodeT32AluImm.Create);
|
||||||
SetT32("111010100001xxxx0xxx1111xxxxxxxx", InstName.Tst, InstEmit32.Tst, OpCodeT32AluRsImm.Create);
|
SetT32("111010100001xxxx0xxx1111xxxxxxxx", InstName.Tst, InstEmit32.Tst, OpCodeT32AluRsImm.Create);
|
||||||
|
@@ -107,5 +107,30 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
context.SetIfThenBlockState(op.IfThenBlockConds);
|
context.SetIfThenBlockState(op.IfThenBlockConds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Tbb(ArmEmitterContext context) => EmitTb(context, halfword: false);
|
||||||
|
public static void Tbh(ArmEmitterContext context) => EmitTb(context, halfword: true);
|
||||||
|
|
||||||
|
private static void EmitTb(ArmEmitterContext context, bool halfword)
|
||||||
|
{
|
||||||
|
OpCodeT32Tb op = (OpCodeT32Tb)context.CurrOp;
|
||||||
|
|
||||||
|
Operand halfwords;
|
||||||
|
|
||||||
|
if (halfword)
|
||||||
|
{
|
||||||
|
Operand address = context.Add(GetIntA32(context, op.Rn), context.ShiftLeft(GetIntA32(context, op.Rm), Const(1)));
|
||||||
|
halfwords = InstEmitMemoryHelper.EmitReadInt(context, address, 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Operand address = context.Add(GetIntA32(context, op.Rn), GetIntA32(context, op.Rm));
|
||||||
|
halfwords = InstEmitMemoryHelper.EmitReadIntAligned(context, address, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand targetAddress = context.Add(Const((int)op.GetPc()), context.ShiftLeft(halfwords, Const(1)));
|
||||||
|
|
||||||
|
EmitVirtualJump(context, targetAddress, isReturn: false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -205,13 +205,13 @@ namespace ARMeilleure.Instructions
|
|||||||
context.BranchIfTrue(lblBigEndian, GetFlag(PState.EFlag));
|
context.BranchIfTrue(lblBigEndian, GetFlag(PState.EFlag));
|
||||||
|
|
||||||
Load(op.Rt, 0, WordSizeLog2);
|
Load(op.Rt, 0, WordSizeLog2);
|
||||||
Load(op.Rt | 1, 4, WordSizeLog2);
|
Load(op.Rt2, 4, WordSizeLog2);
|
||||||
|
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
context.MarkLabel(lblBigEndian);
|
context.MarkLabel(lblBigEndian);
|
||||||
|
|
||||||
Load(op.Rt | 1, 0, WordSizeLog2);
|
Load(op.Rt2, 0, WordSizeLog2);
|
||||||
Load(op.Rt, 4, WordSizeLog2);
|
Load(op.Rt, 4, WordSizeLog2);
|
||||||
|
|
||||||
context.MarkLabel(lblEnd);
|
context.MarkLabel(lblEnd);
|
||||||
@@ -238,13 +238,13 @@ namespace ARMeilleure.Instructions
|
|||||||
context.BranchIfTrue(lblBigEndian, GetFlag(PState.EFlag));
|
context.BranchIfTrue(lblBigEndian, GetFlag(PState.EFlag));
|
||||||
|
|
||||||
Store(op.Rt, 0, WordSizeLog2);
|
Store(op.Rt, 0, WordSizeLog2);
|
||||||
Store(op.Rt | 1, 4, WordSizeLog2);
|
Store(op.Rt2, 4, WordSizeLog2);
|
||||||
|
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
context.MarkLabel(lblBigEndian);
|
context.MarkLabel(lblBigEndian);
|
||||||
|
|
||||||
Store(op.Rt | 1, 0, WordSizeLog2);
|
Store(op.Rt2, 0, WordSizeLog2);
|
||||||
Store(op.Rt, 4, WordSizeLog2);
|
Store(op.Rt, 4, WordSizeLog2);
|
||||||
|
|
||||||
context.MarkLabel(lblEnd);
|
context.MarkLabel(lblEnd);
|
||||||
|
@@ -123,6 +123,41 @@ namespace ARMeilleure.Instructions
|
|||||||
context.CurrOp is OpCodeSimdMemSs);
|
context.CurrOp is OpCodeSimdMemSs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Operand EmitReadInt(ArmEmitterContext context, Operand address, int size)
|
||||||
|
{
|
||||||
|
Operand temp = context.AllocateLocal(size == 3 ? OperandType.I64 : OperandType.I32);
|
||||||
|
|
||||||
|
Operand lblSlowPath = Label();
|
||||||
|
Operand lblEnd = Label();
|
||||||
|
|
||||||
|
Operand physAddr = EmitPtPointerLoad(context, address, lblSlowPath, write: false, size);
|
||||||
|
|
||||||
|
Operand value = default;
|
||||||
|
|
||||||
|
switch (size)
|
||||||
|
{
|
||||||
|
case 0: value = context.Load8 (physAddr); break;
|
||||||
|
case 1: value = context.Load16(physAddr); break;
|
||||||
|
case 2: value = context.Load (OperandType.I32, physAddr); break;
|
||||||
|
case 3: value = context.Load (OperandType.I64, physAddr); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Copy(temp, value);
|
||||||
|
|
||||||
|
if (!context.Memory.Type.IsHostMapped())
|
||||||
|
{
|
||||||
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
|
context.MarkLabel(lblSlowPath, BasicBlockFrequency.Cold);
|
||||||
|
|
||||||
|
context.Copy(temp, EmitReadIntFallback(context, address, size));
|
||||||
|
|
||||||
|
context.MarkLabel(lblEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
private static void EmitReadInt(ArmEmitterContext context, Operand address, int rt, int size)
|
private static void EmitReadInt(ArmEmitterContext context, Operand address, int rt, int size)
|
||||||
{
|
{
|
||||||
Operand lblSlowPath = Label();
|
Operand lblSlowPath = Label();
|
||||||
@@ -419,6 +454,11 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitReadIntFallback(ArmEmitterContext context, Operand address, int rt, int size)
|
private static void EmitReadIntFallback(ArmEmitterContext context, Operand address, int rt, int size)
|
||||||
|
{
|
||||||
|
SetInt(context, rt, EmitReadIntFallback(context, address, size));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Operand EmitReadIntFallback(ArmEmitterContext context, Operand address, int size)
|
||||||
{
|
{
|
||||||
MethodInfo info = null;
|
MethodInfo info = null;
|
||||||
|
|
||||||
@@ -430,7 +470,7 @@ namespace ARMeilleure.Instructions
|
|||||||
case 3: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64)); break;
|
case 3: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64)); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetInt(context, rt, context.Call(info, address));
|
return context.Call(info, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitReadVectorFallback(
|
private static void EmitReadVectorFallback(
|
||||||
|
@@ -545,6 +545,8 @@ namespace ARMeilleure.Instructions
|
|||||||
Strexh,
|
Strexh,
|
||||||
Strh,
|
Strh,
|
||||||
Sxtb16,
|
Sxtb16,
|
||||||
|
Tbb,
|
||||||
|
Tbh,
|
||||||
Teq,
|
Teq,
|
||||||
Trap,
|
Trap,
|
||||||
Tst,
|
Tst,
|
||||||
|
@@ -27,7 +27,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
||||||
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
||||||
|
|
||||||
private const uint InternalVersion = 3677; //! To be incremented manually for each change to the ARMeilleure project.
|
private const uint InternalVersion = 3683; //! To be incremented manually for each change to the ARMeilleure project.
|
||||||
|
|
||||||
private const string ActualDir = "0";
|
private const string ActualDir = "0";
|
||||||
private const string BackupDir = "1";
|
private const string BackupDir = "1";
|
||||||
|
10
README.md
10
README.md
@@ -36,8 +36,8 @@
|
|||||||
|
|
||||||
## Compatibility
|
## Compatibility
|
||||||
|
|
||||||
As of January 2022, Ryujinx has been tested on approximately 3,500 titles; over 3,200 boot past menus and into gameplay, with roughly 2,500 of those being considered playable.
|
As of September 2022, Ryujinx has been tested on approximately 3,600 titles; over 3,400 boot past menus and into gameplay, with roughly 2,700 of those being considered playable. You can check out the compatibility list [here](https://github.com/Ryujinx/Ryujinx-Games-List/issues).
|
||||||
You can check out the compatibility list [here](https://github.com/Ryujinx/Ryujinx-Games-List/issues). Anyone is free to submit an updated test on an existing game entry; simply follow the new issue template and testing guidelines, or post as a reply to the applicable game issue. Use the search function to see if a game has been tested already!
|
Anyone is free to submit a new game test or update an existing game test entry; simply follow the new issue template and testing guidelines, or post as a reply to the applicable game issue. Use the search function to see if a game has been tested already!
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
@@ -118,11 +118,11 @@ If you'd like to support the project financially, Ryujinx has an active Patreon
|
|||||||
<img src="https://images.squarespace-cdn.com/content/v1/560c1d39e4b0b4fae0c9cf2a/1567548955044-WVD994WZP76EWF15T0L3/Patreon+Button.png?format=500w" width="150">
|
<img src="https://images.squarespace-cdn.com/content/v1/560c1d39e4b0b4fae0c9cf2a/1567548955044-WVD994WZP76EWF15T0L3/Patreon+Button.png?format=500w" width="150">
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
All the developers working on the project do so on their free time, but the project has several expenses:
|
All developers working on the project do so in their free time, but the project has several expenses:
|
||||||
* Hackable Nintendo Switch consoles to reverse-engineer the hardware
|
* Hackable Nintendo Switch consoles to reverse-engineer the hardware
|
||||||
* Additional computer hardware for testing purposes (e.g. GPUs to diagnose graphical bugs, etc.)
|
* Additional computer hardware for testing purposes (e.g. GPUs to diagnose graphical bugs, etc.)
|
||||||
* Licenses for various software development tools (e.g. Jetbrains, LDN servers, IDA)
|
* Licenses for various software development tools (e.g. Jetbrains, IDA)
|
||||||
* Web hosting and infrastructure maintenance
|
* Web hosting and infrastructure maintenance (e.g. LDN servers)
|
||||||
|
|
||||||
All funds received through Patreon are considered a donation to support the project. Patrons receive early access to progress reports and exclusive access to developer interviews.
|
All funds received through Patreon are considered a donation to support the project. Patrons receive early access to progress reports and exclusive access to developer interviews.
|
||||||
|
|
||||||
|
@@ -55,7 +55,6 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
private uint _processHandle;
|
private uint _processHandle;
|
||||||
private ulong _appletResourceId;
|
private ulong _appletResourceId;
|
||||||
|
|
||||||
private WritableRegion _workBufferRegion;
|
|
||||||
private MemoryHandle _workBufferMemoryPin;
|
private MemoryHandle _workBufferMemoryPin;
|
||||||
|
|
||||||
private Memory<float> _mixBuffer;
|
private Memory<float> _mixBuffer;
|
||||||
@@ -98,7 +97,15 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
_sessionId = 0;
|
_sessionId = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResultCode Initialize(ref AudioRendererConfiguration parameter, uint processHandle, CpuAddress workBuffer, ulong workBufferSize, int sessionId, ulong appletResourceId, IVirtualMemoryManager memoryManager)
|
public ResultCode Initialize(
|
||||||
|
ref AudioRendererConfiguration parameter,
|
||||||
|
uint processHandle,
|
||||||
|
Memory<byte> workBufferMemory,
|
||||||
|
CpuAddress workBuffer,
|
||||||
|
ulong workBufferSize,
|
||||||
|
int sessionId,
|
||||||
|
ulong appletResourceId,
|
||||||
|
IVirtualMemoryManager memoryManager)
|
||||||
{
|
{
|
||||||
if (!BehaviourContext.CheckValidRevision(parameter.Revision))
|
if (!BehaviourContext.CheckValidRevision(parameter.Revision))
|
||||||
{
|
{
|
||||||
@@ -134,11 +141,10 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
|
|
||||||
WorkBufferAllocator workBufferAllocator;
|
WorkBufferAllocator workBufferAllocator;
|
||||||
|
|
||||||
_workBufferRegion = MemoryManager.GetWritableRegion(workBuffer, (int)workBufferSize);
|
workBufferMemory.Span.Fill(0);
|
||||||
_workBufferRegion.Memory.Span.Fill(0);
|
_workBufferMemoryPin = workBufferMemory.Pin();
|
||||||
_workBufferMemoryPin = _workBufferRegion.Memory.Pin();
|
|
||||||
|
|
||||||
workBufferAllocator = new WorkBufferAllocator(_workBufferRegion.Memory);
|
workBufferAllocator = new WorkBufferAllocator(workBufferMemory);
|
||||||
|
|
||||||
PoolMapper poolMapper = new PoolMapper(processHandle, false);
|
PoolMapper poolMapper = new PoolMapper(processHandle, false);
|
||||||
poolMapper.InitializeSystemPool(ref _dspMemoryPoolState, workBuffer, workBufferSize);
|
poolMapper.InitializeSystemPool(ref _dspMemoryPoolState, workBuffer, workBufferSize);
|
||||||
@@ -841,7 +847,6 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
_manager.Unregister(this);
|
_manager.Unregister(this);
|
||||||
_terminationEvent.Dispose();
|
_terminationEvent.Dispose();
|
||||||
_workBufferMemoryPin.Dispose();
|
_workBufferMemoryPin.Dispose();
|
||||||
_workBufferRegion.Dispose();
|
|
||||||
|
|
||||||
if (MemoryManager is IRefCounted rc)
|
if (MemoryManager is IRefCounted rc)
|
||||||
{
|
{
|
||||||
|
@@ -305,13 +305,34 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
/// <param name="workBufferSize">The guest work buffer size.</param>
|
/// <param name="workBufferSize">The guest work buffer size.</param>
|
||||||
/// <param name="processHandle">The process handle of the application.</param>
|
/// <param name="processHandle">The process handle of the application.</param>
|
||||||
/// <returns>A <see cref="ResultCode"/> reporting an error or a success.</returns>
|
/// <returns>A <see cref="ResultCode"/> reporting an error or a success.</returns>
|
||||||
public ResultCode OpenAudioRenderer(out AudioRenderSystem renderer, IVirtualMemoryManager memoryManager, ref AudioRendererConfiguration parameter, ulong appletResourceUserId, ulong workBufferAddress, ulong workBufferSize, uint processHandle, float volume)
|
public ResultCode OpenAudioRenderer(
|
||||||
|
out AudioRenderSystem renderer,
|
||||||
|
IVirtualMemoryManager memoryManager,
|
||||||
|
ref AudioRendererConfiguration parameter,
|
||||||
|
ulong appletResourceUserId,
|
||||||
|
ulong workBufferAddress,
|
||||||
|
ulong workBufferSize,
|
||||||
|
uint processHandle,
|
||||||
|
float volume)
|
||||||
{
|
{
|
||||||
int sessionId = AcquireSessionId();
|
int sessionId = AcquireSessionId();
|
||||||
|
|
||||||
AudioRenderSystem audioRenderer = new AudioRenderSystem(this, _sessionsSystemEvent[sessionId]);
|
AudioRenderSystem audioRenderer = new AudioRenderSystem(this, _sessionsSystemEvent[sessionId]);
|
||||||
|
|
||||||
ResultCode result = audioRenderer.Initialize(ref parameter, processHandle, workBufferAddress, workBufferSize, sessionId, appletResourceUserId, memoryManager);
|
// TODO: Eventually, we should try to use the guest supplied work buffer instead of allocating
|
||||||
|
// our own. However, it was causing problems on some applications that would unmap the memory
|
||||||
|
// before the audio renderer was fully disposed.
|
||||||
|
Memory<byte> workBufferMemory = GC.AllocateArray<byte>((int)workBufferSize, pinned: true);
|
||||||
|
|
||||||
|
ResultCode result = audioRenderer.Initialize(
|
||||||
|
ref parameter,
|
||||||
|
processHandle,
|
||||||
|
workBufferMemory,
|
||||||
|
workBufferAddress,
|
||||||
|
workBufferSize,
|
||||||
|
sessionId,
|
||||||
|
appletResourceUserId,
|
||||||
|
memoryManager);
|
||||||
|
|
||||||
if (result == ResultCode.Success)
|
if (result == ResultCode.Success)
|
||||||
{
|
{
|
||||||
|
@@ -26,6 +26,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
public readonly bool SupportsNonConstantTextureOffset;
|
public readonly bool SupportsNonConstantTextureOffset;
|
||||||
public readonly bool SupportsShaderBallot;
|
public readonly bool SupportsShaderBallot;
|
||||||
public readonly bool SupportsTextureShadowLod;
|
public readonly bool SupportsTextureShadowLod;
|
||||||
|
public readonly bool SupportsViewportIndex;
|
||||||
public readonly bool SupportsViewportSwizzle;
|
public readonly bool SupportsViewportSwizzle;
|
||||||
public readonly bool SupportsIndirectParameters;
|
public readonly bool SupportsIndirectParameters;
|
||||||
|
|
||||||
@@ -59,6 +60,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
bool supportsNonConstantTextureOffset,
|
bool supportsNonConstantTextureOffset,
|
||||||
bool supportsShaderBallot,
|
bool supportsShaderBallot,
|
||||||
bool supportsTextureShadowLod,
|
bool supportsTextureShadowLod,
|
||||||
|
bool supportsViewportIndex,
|
||||||
bool supportsViewportSwizzle,
|
bool supportsViewportSwizzle,
|
||||||
bool supportsIndirectParameters,
|
bool supportsIndirectParameters,
|
||||||
uint maximumUniformBuffersPerStage,
|
uint maximumUniformBuffersPerStage,
|
||||||
@@ -89,6 +91,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
SupportsNonConstantTextureOffset = supportsNonConstantTextureOffset;
|
SupportsNonConstantTextureOffset = supportsNonConstantTextureOffset;
|
||||||
SupportsShaderBallot = supportsShaderBallot;
|
SupportsShaderBallot = supportsShaderBallot;
|
||||||
SupportsTextureShadowLod = supportsTextureShadowLod;
|
SupportsTextureShadowLod = supportsTextureShadowLod;
|
||||||
|
SupportsViewportIndex = supportsViewportIndex;
|
||||||
SupportsViewportSwizzle = supportsViewportSwizzle;
|
SupportsViewportSwizzle = supportsViewportSwizzle;
|
||||||
SupportsIndirectParameters = supportsIndirectParameters;
|
SupportsIndirectParameters = supportsIndirectParameters;
|
||||||
MaximumUniformBuffersPerStage = maximumUniformBuffersPerStage;
|
MaximumUniformBuffersPerStage = maximumUniformBuffersPerStage;
|
||||||
|
@@ -47,6 +47,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
|
|
||||||
public int TextureHandle;
|
public int TextureHandle;
|
||||||
public int SamplerHandle;
|
public int SamplerHandle;
|
||||||
|
public Format ImageFormat;
|
||||||
public int InvalidatedSequence;
|
public int InvalidatedSequence;
|
||||||
public Texture CachedTexture;
|
public Texture CachedTexture;
|
||||||
public Sampler CachedSampler;
|
public Sampler CachedSampler;
|
||||||
@@ -564,6 +565,9 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
// Buffers are frequently re-created to accomodate larger data, so we need to re-bind
|
// Buffers are frequently re-created to accomodate larger data, so we need to re-bind
|
||||||
// to ensure we're not using a old buffer that was already deleted.
|
// to ensure we're not using a old buffer that was already deleted.
|
||||||
_channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range.GetSubRange(0).Address, texture.Size, bindingInfo, bindingInfo.Format, false);
|
_channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range.GetSubRange(0).Address, texture.Size, bindingInfo, bindingInfo.Format, false);
|
||||||
|
|
||||||
|
// Cache is not used for buffer texture, it must always rebind.
|
||||||
|
state.CachedTexture = null;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -659,14 +663,16 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
cachedTexture?.SignalModified();
|
cachedTexture?.SignalModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((usageFlags & TextureUsageFlags.NeedsScaleValue) != 0 &&
|
Format format = bindingInfo.Format == 0 ? cachedTexture.Format : bindingInfo.Format;
|
||||||
UpdateScale(state.CachedTexture, usageFlags, scaleIndex, stage))
|
|
||||||
|
if (state.ImageFormat != format ||
|
||||||
|
((usageFlags & TextureUsageFlags.NeedsScaleValue) != 0 &&
|
||||||
|
UpdateScale(state.CachedTexture, usageFlags, scaleIndex, stage)))
|
||||||
{
|
{
|
||||||
ITexture hostTextureRebind = state.CachedTexture.GetTargetTexture(bindingInfo.Target);
|
ITexture hostTextureRebind = state.CachedTexture.GetTargetTexture(bindingInfo.Target);
|
||||||
|
|
||||||
Format format = bindingInfo.Format == 0 ? cachedTexture.Format : bindingInfo.Format;
|
|
||||||
|
|
||||||
state.Texture = hostTextureRebind;
|
state.Texture = hostTextureRebind;
|
||||||
|
state.ImageFormat = format;
|
||||||
|
|
||||||
_context.Renderer.Pipeline.SetImage(bindingInfo.Binding, hostTextureRebind, format);
|
_context.Renderer.Pipeline.SetImage(bindingInfo.Binding, hostTextureRebind, format);
|
||||||
}
|
}
|
||||||
@@ -696,6 +702,9 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
}
|
}
|
||||||
|
|
||||||
_channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range.GetSubRange(0).Address, texture.Size, bindingInfo, format, true);
|
_channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range.GetSubRange(0).Address, texture.Size, bindingInfo, format, true);
|
||||||
|
|
||||||
|
// Cache is not used for buffer texture, it must always rebind.
|
||||||
|
state.CachedTexture = null;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -721,6 +730,8 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
format = texture.Format;
|
format = texture.Format;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state.ImageFormat = format;
|
||||||
|
|
||||||
_context.Renderer.Pipeline.SetImage(bindingInfo.Binding, hostTexture, format);
|
_context.Renderer.Pipeline.SetImage(bindingInfo.Binding, hostTexture, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
private const ushort FileFormatVersionMajor = 1;
|
private const ushort FileFormatVersionMajor = 1;
|
||||||
private const ushort FileFormatVersionMinor = 2;
|
private const ushort FileFormatVersionMinor = 2;
|
||||||
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
||||||
private const uint CodeGenVersion = 3672;
|
private const uint CodeGenVersion = 3644;
|
||||||
|
|
||||||
private const string SharedTocFileName = "shared.toc";
|
private const string SharedTocFileName = "shared.toc";
|
||||||
private const string SharedDataFileName = "shared.data";
|
private const string SharedDataFileName = "shared.data";
|
||||||
|
@@ -134,6 +134,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
|
|
||||||
public bool QueryHostSupportsTextureShadowLod() => _context.Capabilities.SupportsTextureShadowLod;
|
public bool QueryHostSupportsTextureShadowLod() => _context.Capabilities.SupportsTextureShadowLod;
|
||||||
|
|
||||||
|
public bool QueryHostSupportsViewportIndex() => _context.Capabilities.SupportsViewportIndex;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converts a packed Maxwell texture format to the shader translator texture format.
|
/// Converts a packed Maxwell texture format to the shader translator texture format.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@@ -120,6 +120,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
supportsNonConstantTextureOffset: HwCapabilities.SupportsNonConstantTextureOffset,
|
supportsNonConstantTextureOffset: HwCapabilities.SupportsNonConstantTextureOffset,
|
||||||
supportsShaderBallot: HwCapabilities.SupportsShaderBallot,
|
supportsShaderBallot: HwCapabilities.SupportsShaderBallot,
|
||||||
supportsTextureShadowLod: HwCapabilities.SupportsTextureShadowLod,
|
supportsTextureShadowLod: HwCapabilities.SupportsTextureShadowLod,
|
||||||
|
supportsViewportIndex: true,
|
||||||
supportsViewportSwizzle: HwCapabilities.SupportsViewportSwizzle,
|
supportsViewportSwizzle: HwCapabilities.SupportsViewportSwizzle,
|
||||||
supportsIndirectParameters: HwCapabilities.SupportsIndirectParameters,
|
supportsIndirectParameters: HwCapabilities.SupportsIndirectParameters,
|
||||||
maximumUniformBuffersPerStage: 13, // TODO: Avoid hardcoding those limits here and get from driver?
|
maximumUniformBuffersPerStage: 13, // TODO: Avoid hardcoding those limits here and get from driver?
|
||||||
|
@@ -267,6 +267,15 @@ namespace Ryujinx.Graphics.Shader
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queries host GPU shader viewport index output support.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if the GPU and driver supports shader viewport index output, false otherwise</returns>
|
||||||
|
bool QueryHostSupportsViewportIndex()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Queries the point size from the GPU state, used when it is not explicitly set on the shader.
|
/// Queries the point size from the GPU state, used when it is not explicitly set on the shader.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@@ -78,6 +78,11 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
|
|
||||||
public static bool Validate(ShaderConfig config, int value, bool isOutAttr)
|
public static bool Validate(ShaderConfig config, int value, bool isOutAttr)
|
||||||
{
|
{
|
||||||
|
if (value == AttributeConsts.ViewportIndex && !config.GpuAccessor.QueryHostSupportsViewportIndex())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return From(config, value, isOutAttr).IsValid;
|
return From(config, value, isOutAttr).IsValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -380,7 +380,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
return BufferManager.GetData(buffer, offset, size);
|
return BufferManager.GetData(buffer, offset, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Capabilities GetCapabilities()
|
public unsafe Capabilities GetCapabilities()
|
||||||
{
|
{
|
||||||
FormatFeatureFlags compressedFormatFeatureFlags =
|
FormatFeatureFlags compressedFormatFeatureFlags =
|
||||||
FormatFeatureFlags.FormatFeatureSampledImageBit |
|
FormatFeatureFlags.FormatFeatureSampledImageBit |
|
||||||
@@ -409,7 +409,19 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
GAL.Format.Bc7Srgb,
|
GAL.Format.Bc7Srgb,
|
||||||
GAL.Format.Bc7Unorm);
|
GAL.Format.Bc7Unorm);
|
||||||
|
|
||||||
Api.GetPhysicalDeviceFeatures(_physicalDevice, out var features);
|
|
||||||
|
PhysicalDeviceVulkan12Features featuresVk12 = new PhysicalDeviceVulkan12Features()
|
||||||
|
{
|
||||||
|
SType = StructureType.PhysicalDeviceVulkan12Features
|
||||||
|
};
|
||||||
|
|
||||||
|
PhysicalDeviceFeatures2 features2 = new PhysicalDeviceFeatures2()
|
||||||
|
{
|
||||||
|
SType = StructureType.PhysicalDeviceFeatures2,
|
||||||
|
PNext = &featuresVk12
|
||||||
|
};
|
||||||
|
|
||||||
|
Api.GetPhysicalDeviceFeatures2(_physicalDevice, &features2);
|
||||||
Api.GetPhysicalDeviceProperties(_physicalDevice, out var properties);
|
Api.GetPhysicalDeviceProperties(_physicalDevice, out var properties);
|
||||||
|
|
||||||
var limits = properties.Limits;
|
var limits = properties.Limits;
|
||||||
@@ -419,7 +431,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
GpuVendor,
|
GpuVendor,
|
||||||
hasFrontFacingBug: IsIntelWindows,
|
hasFrontFacingBug: IsIntelWindows,
|
||||||
hasVectorIndexingBug: Vendor == Vendor.Qualcomm,
|
hasVectorIndexingBug: Vendor == Vendor.Qualcomm,
|
||||||
supportsAstcCompression: features.TextureCompressionAstcLdr,
|
supportsAstcCompression: features2.Features.TextureCompressionAstcLdr,
|
||||||
supportsBc123Compression: supportsBc123CompressionFormat,
|
supportsBc123Compression: supportsBc123CompressionFormat,
|
||||||
supportsBc45Compression: supportsBc45CompressionFormat,
|
supportsBc45Compression: supportsBc45CompressionFormat,
|
||||||
supportsBc67Compression: supportsBc67CompressionFormat,
|
supportsBc67Compression: supportsBc67CompressionFormat,
|
||||||
@@ -429,12 +441,13 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
supportsFragmentShaderInterlock: Capabilities.SupportsFragmentShaderInterlock,
|
supportsFragmentShaderInterlock: Capabilities.SupportsFragmentShaderInterlock,
|
||||||
supportsFragmentShaderOrderingIntel: false,
|
supportsFragmentShaderOrderingIntel: false,
|
||||||
supportsGeometryShaderPassthrough: Capabilities.SupportsGeometryShaderPassthrough,
|
supportsGeometryShaderPassthrough: Capabilities.SupportsGeometryShaderPassthrough,
|
||||||
supportsImageLoadFormatted: features.ShaderStorageImageReadWithoutFormat,
|
supportsImageLoadFormatted: features2.Features.ShaderStorageImageReadWithoutFormat,
|
||||||
supportsMismatchingViewFormat: true,
|
supportsMismatchingViewFormat: true,
|
||||||
supportsCubemapView: !IsAmdGcn,
|
supportsCubemapView: !IsAmdGcn,
|
||||||
supportsNonConstantTextureOffset: false,
|
supportsNonConstantTextureOffset: false,
|
||||||
supportsShaderBallot: false,
|
supportsShaderBallot: false,
|
||||||
supportsTextureShadowLod: false,
|
supportsTextureShadowLod: false,
|
||||||
|
supportsViewportIndex: featuresVk12.ShaderOutputViewportIndex,
|
||||||
supportsViewportSwizzle: false,
|
supportsViewportSwizzle: false,
|
||||||
supportsIndirectParameters: Capabilities.SupportsIndirectParameters,
|
supportsIndirectParameters: Capabilities.SupportsIndirectParameters,
|
||||||
maximumUniformBuffersPerStage: Constants.MaxUniformBuffersPerStage,
|
maximumUniformBuffersPerStage: Constants.MaxUniformBuffersPerStage,
|
||||||
|
@@ -31,11 +31,26 @@ namespace Ryujinx.HLE.HOS.Services.Audio
|
|||||||
return AudioRendererManagerImpl.GetWorkBufferSize(ref parameter);
|
return AudioRendererManagerImpl.GetWorkBufferSize(ref parameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResultCode OpenAudioRenderer(ServiceCtx context, out IAudioRenderer obj, ref AudioRendererConfiguration parameter, ulong workBufferSize, ulong appletResourceUserId, KTransferMemory workBufferTransferMemory, uint processHandle)
|
public ResultCode OpenAudioRenderer(
|
||||||
|
ServiceCtx context,
|
||||||
|
out IAudioRenderer obj,
|
||||||
|
ref AudioRendererConfiguration parameter,
|
||||||
|
ulong workBufferSize,
|
||||||
|
ulong appletResourceUserId,
|
||||||
|
KTransferMemory workBufferTransferMemory,
|
||||||
|
uint processHandle)
|
||||||
{
|
{
|
||||||
var memoryManager = context.Process.HandleTable.GetKProcess((int)processHandle).CpuMemory;
|
var memoryManager = context.Process.HandleTable.GetKProcess((int)processHandle).CpuMemory;
|
||||||
|
|
||||||
ResultCode result = (ResultCode)_impl.OpenAudioRenderer(out AudioRenderSystem renderer, memoryManager, ref parameter, appletResourceUserId, workBufferTransferMemory.Address, workBufferTransferMemory.Size, processHandle, context.Device.Configuration.AudioVolume);
|
ResultCode result = (ResultCode)_impl.OpenAudioRenderer(
|
||||||
|
out AudioRenderSystem renderer,
|
||||||
|
memoryManager,
|
||||||
|
ref parameter,
|
||||||
|
appletResourceUserId,
|
||||||
|
workBufferTransferMemory.Address,
|
||||||
|
workBufferTransferMemory.Size,
|
||||||
|
processHandle,
|
||||||
|
context.Device.Configuration.AudioVolume);
|
||||||
|
|
||||||
if (result == ResultCode.Success)
|
if (result == ResultCode.Success)
|
||||||
{
|
{
|
||||||
|
@@ -34,7 +34,14 @@ namespace Ryujinx.HLE.HOS.Services.Audio
|
|||||||
KTransferMemory workBufferTransferMemory = context.Process.HandleTable.GetObject<KTransferMemory>(transferMemoryHandle);
|
KTransferMemory workBufferTransferMemory = context.Process.HandleTable.GetObject<KTransferMemory>(transferMemoryHandle);
|
||||||
uint processHandle = (uint)context.Request.HandleDesc.ToCopy[1];
|
uint processHandle = (uint)context.Request.HandleDesc.ToCopy[1];
|
||||||
|
|
||||||
ResultCode result = _impl.OpenAudioRenderer(context, out IAudioRenderer renderer, ref parameter, workBufferSize, appletResourceUserId, workBufferTransferMemory, processHandle);
|
ResultCode result = _impl.OpenAudioRenderer(
|
||||||
|
context,
|
||||||
|
out IAudioRenderer renderer,
|
||||||
|
ref parameter,
|
||||||
|
workBufferSize,
|
||||||
|
appletResourceUserId,
|
||||||
|
workBufferTransferMemory,
|
||||||
|
processHandle);
|
||||||
|
|
||||||
if (result == ResultCode.Success)
|
if (result == ResultCode.Success)
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user