mirror of
https://git.suyu.dev/suyu/suyu.git
synced 2024-11-25 22:57:22 +00:00
gl_shader_decompiler: Implement negate, abs, etc. and lots of cleanup.
This commit is contained in:
parent
7639667562
commit
86135864da
2 changed files with 98 additions and 42 deletions
|
@ -56,15 +56,18 @@ union Attribute {
|
||||||
Attribute_0 = 8,
|
Attribute_0 = 8,
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr Index GetIndex() const {
|
union {
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
BitField<24, 6, Index> index;
|
|
||||||
BitField<22, 2, u64> element;
|
BitField<22, 2, u64> element;
|
||||||
BitField<39, 8, u64> reg;
|
BitField<24, 6, Index> index;
|
||||||
BitField<47, 3, u64> size;
|
BitField<47, 3, u64> size;
|
||||||
|
} fmt20;
|
||||||
|
|
||||||
|
union {
|
||||||
|
BitField<30, 2, u64> element;
|
||||||
|
BitField<32, 6, Index> index;
|
||||||
|
} fmt28;
|
||||||
|
|
||||||
|
BitField<39, 8, u64> reg;
|
||||||
u64 value;
|
u64 value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -104,6 +107,7 @@ union OpCode {
|
||||||
enum class Type {
|
enum class Type {
|
||||||
Trivial,
|
Trivial,
|
||||||
Arithmetic,
|
Arithmetic,
|
||||||
|
Ffma,
|
||||||
Flow,
|
Flow,
|
||||||
Memory,
|
Memory,
|
||||||
Unknown,
|
Unknown,
|
||||||
|
@ -210,12 +214,11 @@ union OpCode {
|
||||||
info_table[Id::TEXS] = {Type::Memory, "texs"};
|
info_table[Id::TEXS] = {Type::Memory, "texs"};
|
||||||
info_table[Id::LD_A] = {Type::Memory, "ld_a"};
|
info_table[Id::LD_A] = {Type::Memory, "ld_a"};
|
||||||
info_table[Id::ST_A] = {Type::Memory, "st_a"};
|
info_table[Id::ST_A] = {Type::Memory, "st_a"};
|
||||||
info_table[Id::IPA] = {Type::Arithmetic, "ipa"};
|
|
||||||
info_table[Id::MUFU] = {Type::Arithmetic, "mufu"};
|
info_table[Id::MUFU] = {Type::Arithmetic, "mufu"};
|
||||||
info_table[Id::FFMA_IMM] = {Type::Arithmetic, "ffma_imm"};
|
info_table[Id::FFMA_IMM] = {Type::Ffma, "ffma_imm"};
|
||||||
info_table[Id::FFMA_CR] = {Type::Arithmetic, "ffma_cr"};
|
info_table[Id::FFMA_CR] = {Type::Ffma, "ffma_cr"};
|
||||||
info_table[Id::FFMA_RC] = {Type::Arithmetic, "ffma_rc"};
|
info_table[Id::FFMA_RC] = {Type::Ffma, "ffma_rc"};
|
||||||
info_table[Id::FFMA_RR] = {Type::Arithmetic, "ffma_rr"};
|
info_table[Id::FFMA_RR] = {Type::Ffma, "ffma_rr"};
|
||||||
info_table[Id::FADD_R] = {Type::Arithmetic, "fadd_r"};
|
info_table[Id::FADD_R] = {Type::Arithmetic, "fadd_r"};
|
||||||
info_table[Id::FADD_C] = {Type::Arithmetic, "fadd_c"};
|
info_table[Id::FADD_C] = {Type::Arithmetic, "fadd_c"};
|
||||||
info_table[Id::FADD_IMM] = {Type::Arithmetic, "fadd_imm"};
|
info_table[Id::FADD_IMM] = {Type::Arithmetic, "fadd_imm"};
|
||||||
|
@ -225,6 +228,7 @@ union OpCode {
|
||||||
info_table[Id::FSETP_C] = {Type::Arithmetic, "fsetp_c"};
|
info_table[Id::FSETP_C] = {Type::Arithmetic, "fsetp_c"};
|
||||||
info_table[Id::FSETP_R] = {Type::Arithmetic, "fsetp_r"};
|
info_table[Id::FSETP_R] = {Type::Arithmetic, "fsetp_r"};
|
||||||
info_table[Id::EXIT] = {Type::Trivial, "exit"};
|
info_table[Id::EXIT] = {Type::Trivial, "exit"};
|
||||||
|
info_table[Id::IPA] = {Type::Trivial, "ipa"};
|
||||||
info_table[Id::KIL] = {Type::Flow, "kil"};
|
info_table[Id::KIL] = {Type::Flow, "kil"};
|
||||||
return info_table;
|
return info_table;
|
||||||
}
|
}
|
||||||
|
@ -285,16 +289,31 @@ union Instruction {
|
||||||
}
|
}
|
||||||
|
|
||||||
OpCode opcode;
|
OpCode opcode;
|
||||||
BitField<0, 8, Register> gpr1;
|
BitField<0, 8, Register> gpr0;
|
||||||
BitField<8, 8, Register> gpr2;
|
BitField<8, 8, Register> gpr8;
|
||||||
BitField<16, 4, Pred> pred;
|
BitField<16, 4, Pred> pred;
|
||||||
|
BitField<20, 8, Register> gpr20;
|
||||||
BitField<20, 7, SubOp> sub_op;
|
BitField<20, 7, SubOp> sub_op;
|
||||||
BitField<39, 8, Register> gpr3;
|
BitField<28, 8, Register> gpr28;
|
||||||
BitField<45, 1, u64> nb;
|
BitField<36, 13, u64> imm36;
|
||||||
BitField<46, 1, u64> aa;
|
BitField<39, 8, Register> gpr39;
|
||||||
BitField<48, 1, u64> na;
|
|
||||||
BitField<49, 1, u64> ab;
|
union {
|
||||||
BitField<50, 1, u64> ad;
|
BitField<45, 1, u64> negate_b;
|
||||||
|
BitField<46, 1, u64> abs_a;
|
||||||
|
BitField<48, 1, u64> negate_a;
|
||||||
|
BitField<49, 1, u64> abs_b;
|
||||||
|
BitField<50, 1, u64> abs_d;
|
||||||
|
} alu;
|
||||||
|
|
||||||
|
union {
|
||||||
|
BitField<48, 1, u64> negate_b;
|
||||||
|
BitField<49, 1, u64> negate_c;
|
||||||
|
} ffma;
|
||||||
|
|
||||||
|
BitField<60, 1, u64> is_b_gpr;
|
||||||
|
BitField<59, 1, u64> is_c_gpr;
|
||||||
|
|
||||||
Attribute attribute;
|
Attribute attribute;
|
||||||
Uniform uniform;
|
Uniform uniform;
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ using Tegra::Shader::Attribute;
|
||||||
using Tegra::Shader::Instruction;
|
using Tegra::Shader::Instruction;
|
||||||
using Tegra::Shader::OpCode;
|
using Tegra::Shader::OpCode;
|
||||||
using Tegra::Shader::Register;
|
using Tegra::Shader::Register;
|
||||||
|
using Tegra::Shader::SubOp;
|
||||||
using Tegra::Shader::Uniform;
|
using Tegra::Shader::Uniform;
|
||||||
|
|
||||||
constexpr u32 PROGRAM_END = MAX_PROGRAM_CODE_LENGTH;
|
constexpr u32 PROGRAM_END = MAX_PROGRAM_CODE_LENGTH;
|
||||||
|
@ -235,27 +236,34 @@ private:
|
||||||
|
|
||||||
switch (OpCode::GetInfo(instr.opcode).type) {
|
switch (OpCode::GetInfo(instr.opcode).type) {
|
||||||
case OpCode::Type::Arithmetic: {
|
case OpCode::Type::Arithmetic: {
|
||||||
ASSERT(!instr.nb);
|
ASSERT(!instr.alu.abs_d, "unimplemented");
|
||||||
ASSERT(!instr.aa);
|
|
||||||
ASSERT(!instr.na);
|
|
||||||
ASSERT(!instr.ab);
|
|
||||||
ASSERT(!instr.ad);
|
|
||||||
|
|
||||||
std::string gpr1 = GetRegister(instr.gpr1);
|
std::string dest = GetRegister(instr.gpr0);
|
||||||
std::string gpr2 = GetRegister(instr.gpr2);
|
std::string op_a = instr.alu.negate_a ? "-" : "";
|
||||||
std::string uniform = GetUniform(instr.uniform);
|
op_a += GetRegister(instr.gpr8);
|
||||||
|
if (instr.alu.abs_a) {
|
||||||
|
op_a = "abs(" + op_a + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string op_b = instr.alu.negate_b ? "-" : "";
|
||||||
|
if (instr.is_b_gpr) {
|
||||||
|
op_b += GetRegister(instr.gpr20);
|
||||||
|
} else {
|
||||||
|
op_b += GetUniform(instr.uniform);
|
||||||
|
}
|
||||||
|
if (instr.alu.abs_b) {
|
||||||
|
op_b = "abs(" + op_b + ")";
|
||||||
|
}
|
||||||
|
|
||||||
switch (instr.opcode.EffectiveOpCode()) {
|
switch (instr.opcode.EffectiveOpCode()) {
|
||||||
case OpCode::Id::FMUL_C: {
|
case OpCode::Id::FMUL_C:
|
||||||
SetDest(0, gpr1, gpr2 + " * " + uniform, 1, 1);
|
case OpCode::Id::FMUL_R: {
|
||||||
|
SetDest(0, dest, op_a + " * " + op_b, 1, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OpCode::Id::FADD_C: {
|
case OpCode::Id::FADD_C:
|
||||||
SetDest(0, gpr1, gpr2 + " + " + uniform, 1, 1);
|
case OpCode::Id::FADD_R: {
|
||||||
break;
|
SetDest(0, dest, op_a + " + " + op_b, 1, 1);
|
||||||
}
|
|
||||||
case OpCode::Id::FFMA_CR: {
|
|
||||||
SetDest(0, gpr1, gpr2 + " * " + uniform + " + " + GetRegister(instr.gpr3), 1, 1);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
@ -268,19 +276,48 @@ private:
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OpCode::Type::Memory: {
|
case OpCode::Type::Ffma: {
|
||||||
ASSERT(instr.attribute.size == 0);
|
ASSERT_MSG(!instr.ffma.negate_b, "untested");
|
||||||
|
ASSERT_MSG(!instr.ffma.negate_c, "untested");
|
||||||
|
|
||||||
std::string gpr1 = GetRegister(instr.gpr1);
|
std::string dest = GetRegister(instr.gpr0);
|
||||||
const Attribute::Index attribute = instr.attribute.GetIndex();
|
std::string op_a = GetRegister(instr.gpr8);
|
||||||
|
|
||||||
|
std::string op_b = instr.ffma.negate_b ? "-" : "";
|
||||||
|
op_b += GetUniform(instr.uniform);
|
||||||
|
|
||||||
|
std::string op_c = instr.ffma.negate_c ? "-" : "";
|
||||||
|
op_c += GetRegister(instr.gpr39);
|
||||||
|
|
||||||
|
switch (instr.opcode.EffectiveOpCode()) {
|
||||||
|
case OpCode::Id::FFMA_CR: {
|
||||||
|
SetDest(0, dest, op_a + " * " + op_b + " + " + op_c, 1, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
LOG_ERROR(HW_GPU, "Unhandled arithmetic FFMA instruction: 0x%02x (%s): 0x%08x",
|
||||||
|
(int)instr.opcode.EffectiveOpCode(), OpCode::GetInfo(instr.opcode).name,
|
||||||
|
instr.hex);
|
||||||
|
throw DecompileFail("Unhandled instruction");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OpCode::Type::Memory: {
|
||||||
|
std::string gpr0 = GetRegister(instr.gpr0);
|
||||||
|
const Attribute::Index attribute = instr.attribute.fmt20.index;
|
||||||
|
|
||||||
switch (instr.opcode.EffectiveOpCode()) {
|
switch (instr.opcode.EffectiveOpCode()) {
|
||||||
case OpCode::Id::LD_A: {
|
case OpCode::Id::LD_A: {
|
||||||
SetDest(instr.attribute.element, gpr1, GetInputAttribute(attribute), 1, 4);
|
ASSERT(instr.attribute.fmt20.size == 0);
|
||||||
|
SetDest(instr.attribute.fmt20.element, gpr0, GetInputAttribute(attribute), 1, 4);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OpCode::Id::ST_A: {
|
case OpCode::Id::ST_A: {
|
||||||
SetDest(instr.attribute.element, GetOutputAttribute(attribute), gpr1, 4, 1);
|
ASSERT(instr.attribute.fmt20.size == 0);
|
||||||
|
SetDest(instr.attribute.fmt20.element, GetOutputAttribute(attribute), gpr0, 4, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
|
Loading…
Reference in a new issue