aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReinUsesLisp <reinuseslisp@airmail.cc>2018-07-17 16:50:00 -0300
committergdkchan <gab.dark.100@gmail.com>2018-07-17 16:50:00 -0300
commit571848536b347a85c85955745a16d4f7b9a0c04a (patch)
treec953477670bf892fd746baeffbe0cfe036952366
parentc2c765b30fdfa9184df580133e22ae946eebc022 (diff)
Implement some shader instructions (#252)
* Add IADDI32, IADD and SEL shader instructions * Add LOP shader instruction and fix LOP32I pass_b * Add ISET shader instruction * Add IADD3 shader instruction * Address feedback * Fixup OperA in Iadd_I32
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs214
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs5
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs37
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs16
4 files changed, 269 insertions, 3 deletions
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs
index 2e022fbd..a4407351 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs
@@ -144,6 +144,50 @@ namespace Ryujinx.Graphics.Gal.Shader
EmitFsetp(Block, OpCode, ShaderOper.RR);
}
+ public static void Iadd_C(ShaderIrBlock Block, long OpCode)
+ {
+ EmitIadd(Block, OpCode, ShaderOper.CR);
+ }
+
+ public static void Iadd_I(ShaderIrBlock Block, long OpCode)
+ {
+ EmitIadd(Block, OpCode, ShaderOper.Imm);
+ }
+
+ public static void Iadd_I32(ShaderIrBlock Block, long OpCode)
+ {
+ ShaderIrNode OperA = GetOperGpr8 (OpCode);
+ ShaderIrNode OperB = GetOperImm32_20(OpCode);
+
+ bool NegA = ((OpCode >> 56) & 1) != 0;
+
+ OperA = GetAluIneg(OperA, NegA);
+
+ ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Add, OperA, OperB);
+
+ Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
+ }
+
+ public static void Iadd_R(ShaderIrBlock Block, long OpCode)
+ {
+ EmitIadd(Block, OpCode, ShaderOper.RR);
+ }
+
+ public static void Iadd3_C(ShaderIrBlock Block, long OpCode)
+ {
+ EmitIadd3(Block, OpCode, ShaderOper.CR);
+ }
+
+ public static void Iadd3_I(ShaderIrBlock Block, long OpCode)
+ {
+ EmitIadd3(Block, OpCode, ShaderOper.Imm);
+ }
+
+ public static void Iadd3_R(ShaderIrBlock Block, long OpCode)
+ {
+ EmitIadd3(Block, OpCode, ShaderOper.RR);
+ }
+
public static void Imnmx_C(ShaderIrBlock Block, long OpCode)
{
EmitImnmx(Block, OpCode, ShaderOper.CR);
@@ -184,6 +228,21 @@ namespace Ryujinx.Graphics.Gal.Shader
EmitIscadd(Block, OpCode, ShaderOper.RR);
}
+ public static void Iset_C(ShaderIrBlock Block, long OpCode)
+ {
+ EmitIset(Block, OpCode, ShaderOper.CR);
+ }
+
+ public static void Iset_I(ShaderIrBlock Block, long OpCode)
+ {
+ EmitIset(Block, OpCode, ShaderOper.Imm);
+ }
+
+ public static void Iset_R(ShaderIrBlock Block, long OpCode)
+ {
+ EmitIset(Block, OpCode, ShaderOper.RR);
+ }
+
public static void Isetp_C(ShaderIrBlock Block, long OpCode)
{
EmitIsetp(Block, OpCode, ShaderOper.CR);
@@ -215,13 +274,13 @@ namespace Ryujinx.Graphics.Gal.Shader
case 2: Inst = ShaderIrInst.Xor; break;
}
- ShaderIrNode OperA = GetAluNot(GetOperGpr8(OpCode), InvA);
+ ShaderIrNode OperB = GetAluNot(GetOperImm32_20(OpCode), InvB);
//SubOp == 3 is pass, used by the not instruction
//which just moves the inverted register value.
if (SubOp < 3)
{
- ShaderIrNode OperB = GetAluNot(GetOperImm32_20(OpCode), InvB);
+ ShaderIrNode OperA = GetAluNot(GetOperGpr8(OpCode), InvA);
ShaderIrOp Op = new ShaderIrOp(Inst, OperA, OperB);
@@ -229,10 +288,25 @@ namespace Ryujinx.Graphics.Gal.Shader
}
else
{
- Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), OperA), OpCode));
+ Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), OperB), OpCode));
}
}
+ public static void Lop_C(ShaderIrBlock Block, long OpCode)
+ {
+ EmitLop(Block, OpCode, ShaderOper.CR);
+ }
+
+ public static void Lop_I(ShaderIrBlock Block, long OpCode)
+ {
+ EmitLop(Block, OpCode, ShaderOper.Imm);
+ }
+
+ public static void Lop_R(ShaderIrBlock Block, long OpCode)
+ {
+ EmitLop(Block, OpCode, ShaderOper.RR);
+ }
+
public static void Mufu(ShaderIrBlock Block, long OpCode)
{
int SubOp = (int)(OpCode >> 20) & 0xf;
@@ -533,6 +607,92 @@ namespace Ryujinx.Graphics.Gal.Shader
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
}
+ private static void EmitIadd(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
+ {
+ ShaderIrNode OperA = GetOperGpr8(OpCode);
+ ShaderIrNode OperB;
+
+ switch (Oper)
+ {
+ case ShaderOper.CR: OperB = GetOperCbuf34 (OpCode); break;
+ case ShaderOper.Imm: OperB = GetOperImm19_20(OpCode); break;
+ case ShaderOper.RR: OperB = GetOperGpr20 (OpCode); break;
+
+ default: throw new ArgumentException(nameof(Oper));
+ }
+
+ bool NegA = ((OpCode >> 49) & 1) != 0;
+ bool NegB = ((OpCode >> 48) & 1) != 0;
+
+ OperA = GetAluIneg(OperA, NegA);
+ OperB = GetAluIneg(OperB, NegB);
+
+ ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Add, OperA, OperB);
+
+ Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
+ }
+
+ private static void EmitIadd3(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
+ {
+ int Mode = (int)((OpCode >> 37) & 3);
+
+ bool Neg1 = ((OpCode >> 51) & 1) != 0;
+ bool Neg2 = ((OpCode >> 50) & 1) != 0;
+ bool Neg3 = ((OpCode >> 49) & 1) != 0;
+
+ int Height1 = (int)((OpCode >> 35) & 3);
+ int Height2 = (int)((OpCode >> 33) & 3);
+ int Height3 = (int)((OpCode >> 31) & 3);
+
+ ShaderIrNode OperB;
+
+ switch (Oper)
+ {
+ case ShaderOper.CR: OperB = GetOperCbuf34 (OpCode); break;
+ case ShaderOper.Imm: OperB = GetOperImm19_20(OpCode); break;
+ case ShaderOper.RR: OperB = GetOperGpr20 (OpCode); break;
+
+ default: throw new ArgumentException(nameof(Oper));
+ }
+
+ ShaderIrNode ApplyHeight(ShaderIrNode Src, int Height)
+ {
+ if (Oper != ShaderOper.RR)
+ {
+ return Src;
+ }
+
+ switch (Height)
+ {
+ case 0: return Src;
+ case 1: return new ShaderIrOp(ShaderIrInst.And, Src, new ShaderIrOperImm(0xffff));
+ case 2: return new ShaderIrOp(ShaderIrInst.Lsr, Src, new ShaderIrOperImm(16));
+
+ default: throw new InvalidOperationException();
+ }
+ }
+
+ ShaderIrNode Src1 = GetAluIneg(ApplyHeight(GetOperGpr8(OpCode), Height1), Neg1);
+ ShaderIrNode Src2 = GetAluIneg(ApplyHeight(OperB, Height2), Neg2);
+ ShaderIrNode Src3 = GetAluIneg(ApplyHeight(GetOperGpr39(OpCode), Height3), Neg3);
+
+ ShaderIrOp Sum = new ShaderIrOp(ShaderIrInst.Add, Src1, Src2);
+
+ if (Oper == ShaderOper.RR)
+ {
+ switch (Mode)
+ {
+ case 1: Sum = new ShaderIrOp(ShaderIrInst.Lsr, Sum, new ShaderIrOperImm(16)); break;
+ case 2: Sum = new ShaderIrOp(ShaderIrInst.Lsl, Sum, new ShaderIrOperImm(16)); break;
+ }
+ }
+
+ //Note: Here there should be a "+ 1" when carry flag is set
+ //but since carry is mostly ignored by other instructions, it's excluded for now
+
+ Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), new ShaderIrOp(ShaderIrInst.Add, Sum, Src3)), OpCode));
+ }
+
private static void EmitIscadd(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
{
bool NegB = ((OpCode >> 48) & 1) != 0;
@@ -821,6 +981,54 @@ namespace Ryujinx.Graphics.Gal.Shader
Block.AddNode(GetPredNode(new ShaderIrAsg(P0Node, Op), OpCode));
}
+ private static void EmitLop(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
+ {
+ int SubOp = (int)(OpCode >> 41) & 3;
+
+ bool InvA = ((OpCode >> 39) & 1) != 0;
+ bool InvB = ((OpCode >> 40) & 1) != 0;
+
+ ShaderIrInst Inst = 0;
+
+ switch (SubOp)
+ {
+ case 0: Inst = ShaderIrInst.And; break;
+ case 1: Inst = ShaderIrInst.Or; break;
+ case 2: Inst = ShaderIrInst.Xor; break;
+ }
+
+ ShaderIrNode OperA = GetAluNot(GetOperGpr8(OpCode), InvA);
+ ShaderIrNode OperB;
+
+ switch (Oper)
+ {
+ case ShaderOper.CR: OperB = GetOperCbuf34 (OpCode); break;
+ case ShaderOper.Imm: OperB = GetOperImm19_20(OpCode); break;
+ case ShaderOper.RR: OperB = GetOperGpr20 (OpCode); break;
+
+ default: throw new ArgumentException(nameof(Oper));
+ }
+
+ OperB = GetAluNot(OperB, InvB);
+
+ ShaderIrNode Op;
+
+ if (SubOp < 3)
+ {
+ Op = new ShaderIrOp(Inst, OperA, OperB);
+ }
+ else
+ {
+ Op = OperB;
+ }
+
+ ShaderIrNode Compare = new ShaderIrOp(ShaderIrInst.Cne, Op, new ShaderIrOperImm(0));
+
+ Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperPred48(OpCode), Compare), OpCode));
+
+ Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
+ }
+
private static void EmitXmad(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
{
//TODO: Confirm SignAB/C, it is just a guess.
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs
index a8ad5ec2..1f1b158e 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs
@@ -156,6 +156,11 @@ namespace Ryujinx.Graphics.Gal.Shader
return new ShaderIrOperPred((int)(OpCode >> 39) & 7);
}
+ public static ShaderIrOperPred GetOperPred48(long OpCode)
+ {
+ return new ShaderIrOperPred((int)((OpCode >> 48) & 7));
+ }
+
public static ShaderIrInst GetCmp(long OpCode)
{
switch ((int)(OpCode >> 49) & 7)
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs
index dfcea905..4c9e59cf 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs
@@ -113,6 +113,21 @@ namespace Ryujinx.Graphics.Gal.Shader
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Gpr), OpCode));
}
+ public static void Sel_C(ShaderIrBlock Block, long OpCode)
+ {
+ EmitSel(Block, OpCode, ShaderOper.CR);
+ }
+
+ public static void Sel_I(ShaderIrBlock Block, long OpCode)
+ {
+ EmitSel(Block, OpCode, ShaderOper.Imm);
+ }
+
+ public static void Sel_R(ShaderIrBlock Block, long OpCode)
+ {
+ EmitSel(Block, OpCode, ShaderOper.RR);
+ }
+
private static void EmitF2f(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
{
bool NegA = ((OpCode >> 45) & 1) != 0;
@@ -340,6 +355,28 @@ namespace Ryujinx.Graphics.Gal.Shader
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), OperA), OpCode));
}
+ private static void EmitSel(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
+ {
+ ShaderIrOperGpr Dst = GetOperGpr0 (OpCode);
+ ShaderIrNode Pred = GetOperPred39N(OpCode);
+
+ ShaderIrNode ResultA = GetOperGpr8(OpCode);
+ ShaderIrNode ResultB;
+
+ switch (Oper)
+ {
+ case ShaderOper.CR: ResultB = GetOperCbuf34 (OpCode); break;
+ case ShaderOper.Imm: ResultB = GetOperImm19_20(OpCode); break;
+ case ShaderOper.RR: ResultB = GetOperGpr20 (OpCode); break;
+
+ default: throw new ArgumentException(nameof(Oper));
+ }
+
+ Block.AddNode(GetPredNode(new ShaderIrCond(Pred, new ShaderIrAsg(Dst, ResultA), false), OpCode));
+
+ Block.AddNode(GetPredNode(new ShaderIrCond(Pred, new ShaderIrAsg(Dst, ResultB), true), OpCode));
+ }
+
private static IntType GetIntType(long OpCode)
{
bool Signed = ((OpCode >> 13) & 1) != 0;
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs b/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs
index b4f51e50..1ac11785 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs
@@ -64,6 +64,13 @@ namespace Ryujinx.Graphics.Gal.Shader
Set("0100110011100x", ShaderDecode.I2i_C);
Set("0011100x11100x", ShaderDecode.I2i_I);
Set("0101110011100x", ShaderDecode.I2i_R);
+ Set("0100110000010x", ShaderDecode.Iadd_C);
+ Set("0011100000010x", ShaderDecode.Iadd_I);
+ Set("0001110x0xxxxx", ShaderDecode.Iadd_I32);
+ Set("0101110000010x", ShaderDecode.Iadd_R);
+ Set("010011001100xx", ShaderDecode.Iadd3_C);
+ Set("001110001100xx", ShaderDecode.Iadd3_I);
+ Set("010111001100xx", ShaderDecode.Iadd3_R);
Set("0100110000100x", ShaderDecode.Imnmx_C);
Set("0011100x00100x", ShaderDecode.Imnmx_I);
Set("0101110000100x", ShaderDecode.Imnmx_R);
@@ -71,13 +78,19 @@ namespace Ryujinx.Graphics.Gal.Shader
Set("0100110000011x", ShaderDecode.Iscadd_C);
Set("0011100x00011x", ShaderDecode.Iscadd_I);
Set("0101110000011x", ShaderDecode.Iscadd_R);
+ Set("010010110101xx", ShaderDecode.Iset_C);
+ Set("001101100101xx", ShaderDecode.Iset_I);
+ Set("010110110101xx", ShaderDecode.Iset_R);
Set("010010110110xx", ShaderDecode.Isetp_C);
Set("0011011x0110xx", ShaderDecode.Isetp_I);
Set("010110110110xx", ShaderDecode.Isetp_R);
Set("111000110011xx", ShaderDecode.Kil);
Set("1110111111011x", ShaderDecode.Ld_A);
Set("1110111110010x", ShaderDecode.Ld_C);
+ Set("0100110001000x", ShaderDecode.Lop_C);
+ Set("0011100001000x", ShaderDecode.Lop_I);
Set("000001xxxxxxxx", ShaderDecode.Lop_I32);
+ Set("0101110001000x", ShaderDecode.Lop_R);
Set("0100110010011x", ShaderDecode.Mov_C);
Set("0011100x10011x", ShaderDecode.Mov_I);
Set("000000010000xx", ShaderDecode.Mov_I32);
@@ -87,6 +100,9 @@ namespace Ryujinx.Graphics.Gal.Shader
Set("0100110010010x", ShaderDecode.Rro_C);
Set("0011100x10010x", ShaderDecode.Rro_I);
Set("0101110010010x", ShaderDecode.Rro_R);
+ Set("0100110010100x", ShaderDecode.Sel_C);
+ Set("0011100010100x", ShaderDecode.Sel_I);
+ Set("0101110010100x", ShaderDecode.Sel_R);
Set("0100110001001x", ShaderDecode.Shl_C);
Set("0011100x01001x", ShaderDecode.Shl_I);
Set("0101110001001x", ShaderDecode.Shl_R);