summaryrefslogtreecommitdiffstats
path: root/src/shader_recompiler/frontend/maxwell/translate
diff options
context:
space:
mode:
Diffstat (limited to 'src/shader_recompiler/frontend/maxwell/translate')
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/common_encoding.h56
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_add.cpp71
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_fused_multiply_add.cpp73
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_multiply.cpp108
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp26
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/impl.h9
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/integer_add.cpp106
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/integer_scaled_add.cpp73
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/integer_set_predicate.cpp99
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/integer_shift_left.cpp71
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/integer_short_multiply_add.cpp110
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/load_store_memory.cpp149
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/move_register.cpp (renamed from src/shader_recompiler/frontend/maxwell/translate/impl/register_move.cpp)2
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/move_special_register.cpp114
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp149
15 files changed, 1038 insertions, 178 deletions
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/common_encoding.h b/src/shader_recompiler/frontend/maxwell/translate/impl/common_encoding.h
new file mode 100644
index 000000000..3da37a2bb
--- /dev/null
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/common_encoding.h
@@ -0,0 +1,56 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+#include "shader_recompiler/exception.h"
+#include "shader_recompiler/frontend/ir/modifiers.h"
+#include "shader_recompiler/frontend/maxwell/translate/impl/common_encoding.h"
+
+namespace Shader::Maxwell {
+
+enum class FpRounding : u64 {
+ RN,
+ RM,
+ RP,
+ RZ,
+};
+
+enum class FmzMode : u64 {
+ None,
+ FTZ,
+ FMZ,
+ INVALIDFMZ3,
+};
+
+inline IR::FpRounding CastFpRounding(FpRounding fp_rounding) {
+ switch (fp_rounding) {
+ case FpRounding::RN:
+ return IR::FpRounding::RN;
+ case FpRounding::RM:
+ return IR::FpRounding::RM;
+ case FpRounding::RP:
+ return IR::FpRounding::RP;
+ case FpRounding::RZ:
+ return IR::FpRounding::RZ;
+ }
+ throw NotImplementedException("Invalid floating-point rounding {}", fp_rounding);
+}
+
+inline IR::FmzMode CastFmzMode(FmzMode fmz_mode) {
+ switch (fmz_mode) {
+ case FmzMode::None:
+ return IR::FmzMode::None;
+ case FmzMode::FTZ:
+ return IR::FmzMode::FTZ;
+ case FmzMode::FMZ:
+ return IR::FmzMode::FMZ;
+ case FmzMode::INVALIDFMZ3:
+ break;
+ }
+ throw NotImplementedException("Invalid FMZ mode {}", fmz_mode);
+}
+
+} // namespace Shader::Maxwell
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_add.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_add.cpp
new file mode 100644
index 000000000..d2c44b9cc
--- /dev/null
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_add.cpp
@@ -0,0 +1,71 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/common_types.h"
+#include "shader_recompiler/exception.h"
+#include "shader_recompiler/frontend/maxwell/translate/impl/common_encoding.h"
+#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
+
+namespace Shader::Maxwell {
+namespace {
+
+void FADD(TranslatorVisitor& v, u64 insn, bool sat, bool cc, bool ftz, FpRounding fp_rounding,
+ const IR::U32& src_b, bool abs_a, bool neg_a, bool abs_b, bool neg_b) {
+ union {
+ u64 raw;
+ BitField<0, 8, IR::Reg> dest_reg;
+ BitField<8, 8, IR::Reg> src_a;
+ } const fadd{insn};
+
+ if (sat) {
+ throw NotImplementedException("FADD SAT");
+ }
+ if (cc) {
+ throw NotImplementedException("FADD CC");
+ }
+ const IR::U32 op_a{v.ir.FPAbsNeg(v.X(fadd.src_a), abs_a, neg_a)};
+ const IR::U32 op_b{v.ir.FPAbsNeg(src_b, abs_b, neg_b)};
+ IR::FpControl control{
+ .no_contraction{true},
+ .rounding{CastFpRounding(fp_rounding)},
+ .fmz_mode{ftz ? IR::FmzMode::FTZ : IR::FmzMode::None},
+ };
+ v.X(fadd.dest_reg, v.ir.FPAdd(op_a, op_b, control));
+}
+
+void FADD(TranslatorVisitor& v, u64 insn, const IR::U32& src_b) {
+ union {
+ u64 raw;
+ BitField<39, 2, FpRounding> fp_rounding;
+ BitField<44, 1, u64> ftz;
+ BitField<45, 1, u64> neg_b;
+ BitField<46, 1, u64> abs_a;
+ BitField<47, 1, u64> cc;
+ BitField<48, 1, u64> neg_a;
+ BitField<49, 1, u64> abs_b;
+ BitField<50, 1, u64> sat;
+ } const fadd{insn};
+
+ FADD(v, insn, fadd.sat != 0, fadd.cc != 0, fadd.ftz != 0, fadd.fp_rounding, src_b,
+ fadd.abs_a != 0, fadd.neg_a != 0, fadd.abs_b != 0, fadd.neg_b != 0);
+}
+} // Anonymous namespace
+
+void TranslatorVisitor::FADD_reg(u64 insn) {
+ FADD(*this, insn, GetReg20(insn));
+}
+
+void TranslatorVisitor::FADD_cbuf(u64) {
+ throw NotImplementedException("FADD (cbuf)");
+}
+
+void TranslatorVisitor::FADD_imm(u64) {
+ throw NotImplementedException("FADD (imm)");
+}
+
+void TranslatorVisitor::FADD32I(u64) {
+ throw NotImplementedException("FADD32I");
+}
+
+} // namespace Shader::Maxwell
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_fused_multiply_add.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_fused_multiply_add.cpp
new file mode 100644
index 000000000..30ca052ec
--- /dev/null
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_fused_multiply_add.cpp
@@ -0,0 +1,73 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/common_types.h"
+#include "shader_recompiler/exception.h"
+#include "shader_recompiler/frontend/maxwell/translate/impl/common_encoding.h"
+#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
+
+namespace Shader::Maxwell {
+namespace {
+void FFMA(TranslatorVisitor& v, u64 insn, const IR::U32& src_b, const IR::U32& src_c, bool neg_a,
+ bool neg_b, bool neg_c, bool sat, bool cc, FmzMode fmz_mode, FpRounding fp_rounding) {
+ union {
+ u64 raw;
+ BitField<0, 8, IR::Reg> dest_reg;
+ BitField<8, 8, IR::Reg> src_a;
+ } const ffma{insn};
+
+ if (sat) {
+ throw NotImplementedException("FFMA SAT");
+ }
+ if (cc) {
+ throw NotImplementedException("FFMA CC");
+ }
+ const IR::U32 op_a{v.ir.FPAbsNeg(v.X(ffma.src_a), false, neg_a)};
+ const IR::U32 op_b{v.ir.FPAbsNeg(src_b, false, neg_b)};
+ const IR::U32 op_c{v.ir.FPAbsNeg(src_c, false, neg_c)};
+ const IR::FpControl fp_control{
+ .no_contraction{true},
+ .rounding{CastFpRounding(fp_rounding)},
+ .fmz_mode{CastFmzMode(fmz_mode)},
+ };
+ v.X(ffma.dest_reg, v.ir.FPFma(op_a, op_b, op_c, fp_control));
+}
+
+void FFMA(TranslatorVisitor& v, u64 insn, const IR::U32& src_b, const IR::U32& src_c) {
+ union {
+ u64 raw;
+ BitField<47, 1, u64> cc;
+ BitField<48, 1, u64> neg_b;
+ BitField<49, 1, u64> neg_c;
+ BitField<50, 1, u64> sat;
+ BitField<51, 2, FpRounding> fp_rounding;
+ BitField<53, 2, FmzMode> fmz_mode;
+ } const ffma{insn};
+
+ FFMA(v, insn, src_b, src_c, false, ffma.neg_b != 0, ffma.neg_c != 0, ffma.sat != 0,
+ ffma.cc != 0, ffma.fmz_mode, ffma.fp_rounding);
+}
+} // Anonymous namespace
+
+void TranslatorVisitor::FFMA_reg(u64 insn) {
+ FFMA(*this, insn, GetReg20(insn), GetReg39(insn));
+}
+
+void TranslatorVisitor::FFMA_rc(u64) {
+ throw NotImplementedException("FFMA (rc)");
+}
+
+void TranslatorVisitor::FFMA_cr(u64 insn) {
+ FFMA(*this, insn, GetCbuf(insn), GetReg39(insn));
+}
+
+void TranslatorVisitor::FFMA_imm(u64) {
+ throw NotImplementedException("FFMA (imm)");
+}
+
+void TranslatorVisitor::FFMA32I(u64) {
+ throw NotImplementedException("FFMA32I");
+}
+
+} // namespace Shader::Maxwell
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_multiply.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_multiply.cpp
new file mode 100644
index 000000000..743a1e2f0
--- /dev/null
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_multiply.cpp
@@ -0,0 +1,108 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/bit_field.h"
+#include "common/common_types.h"
+#include "shader_recompiler/frontend/ir/modifiers.h"
+#include "shader_recompiler/frontend/maxwell/translate/impl/common_encoding.h"
+#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
+
+namespace Shader::Maxwell {
+namespace {
+enum class Scale : u64 {
+ None,
+ D2,
+ D4,
+ D8,
+ M8,
+ M4,
+ M2,
+ INVALIDSCALE37,
+};
+
+float ScaleFactor(Scale scale) {
+ switch (scale) {
+ case Scale::None:
+ return 1.0f;
+ case Scale::D2:
+ return 1.0f / 2.0f;
+ case Scale::D4:
+ return 1.0f / 4.0f;
+ case Scale::D8:
+ return 1.0f / 8.0f;
+ case Scale::M8:
+ return 8.0f;
+ case Scale::M4:
+ return 4.0f;
+ case Scale::M2:
+ return 2.0f;
+ case Scale::INVALIDSCALE37:
+ break;
+ }
+ throw NotImplementedException("Invalid FMUL scale {}", scale);
+}
+
+void FMUL(TranslatorVisitor& v, u64 insn, const IR::U32& src_b, FmzMode fmz_mode,
+ FpRounding fp_rounding, Scale scale, bool sat, bool cc, bool neg_b) {
+ union {
+ u64 raw;
+ BitField<0, 8, IR::Reg> dest_reg;
+ BitField<8, 8, IR::Reg> src_a;
+ } const fmul{insn};
+
+ if (cc) {
+ throw NotImplementedException("FMUL CC");
+ }
+ if (sat) {
+ throw NotImplementedException("FMUL SAT");
+ }
+ IR::U32 op_a{v.X(fmul.src_a)};
+ if (scale != Scale::None) {
+ if (fmz_mode != FmzMode::FTZ || fp_rounding != FpRounding::RN) {
+ throw NotImplementedException("FMUL scale with non-FMZ or non-RN modifiers");
+ }
+ op_a = v.ir.FPMul(op_a, v.ir.Imm32(ScaleFactor(scale)));
+ }
+ const IR::U32 op_b{v.ir.FPAbsNeg(src_b, false, neg_b)};
+ const IR::FpControl fp_control{
+ .no_contraction{true},
+ .rounding{CastFpRounding(fp_rounding)},
+ .fmz_mode{CastFmzMode(fmz_mode)},
+ };
+ v.X(fmul.dest_reg, v.ir.FPMul(op_a, op_b, fp_control));
+}
+
+void FMUL(TranslatorVisitor& v, u64 insn, const IR::U32& src_b) {
+ union {
+ u64 raw;
+ BitField<39, 2, FpRounding> fp_rounding;
+ BitField<41, 3, Scale> scale;
+ BitField<44, 2, FmzMode> fmz;
+ BitField<47, 1, u64> cc;
+ BitField<48, 1, u64> neg_b;
+ BitField<50, 1, u64> sat;
+ } fmul{insn};
+
+ FMUL(v, insn, src_b, fmul.fmz, fmul.fp_rounding, fmul.scale, fmul.sat != 0, fmul.cc != 0,
+ fmul.neg_b != 0);
+}
+} // Anonymous namespace
+
+void TranslatorVisitor::FMUL_reg(u64 insn) {
+ return FMUL(*this, insn, GetReg20(insn));
+}
+
+void TranslatorVisitor::FMUL_cbuf(u64) {
+ throw NotImplementedException("FMUL (cbuf)");
+}
+
+void TranslatorVisitor::FMUL_imm(u64) {
+ throw NotImplementedException("FMUL (imm)");
+}
+
+void TranslatorVisitor::FMUL32I(u64) {
+ throw NotImplementedException("FMUL32I");
+}
+
+} // namespace Shader::Maxwell \ No newline at end of file
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp
index 7bc7ce9f2..548c7f611 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp
@@ -16,6 +16,22 @@ void TranslatorVisitor::X(IR::Reg dest_reg, const IR::U32& value) {
ir.SetReg(dest_reg, value);
}
+IR::U32 TranslatorVisitor::GetReg20(u64 insn) {
+ union {
+ u64 raw;
+ BitField<20, 8, IR::Reg> index;
+ } const reg{insn};
+ return X(reg.index);
+}
+
+IR::U32 TranslatorVisitor::GetReg39(u64 insn) {
+ union {
+ u64 raw;
+ BitField<39, 8, IR::Reg> index;
+ } const reg{insn};
+ return X(reg.index);
+}
+
IR::U32 TranslatorVisitor::GetCbuf(u64 insn) {
union {
u64 raw;
@@ -33,7 +49,7 @@ IR::U32 TranslatorVisitor::GetCbuf(u64 insn) {
return ir.GetCbuf(binding, byte_offset);
}
-IR::U32 TranslatorVisitor::GetImm(u64 insn) {
+IR::U32 TranslatorVisitor::GetImm20(u64 insn) {
union {
u64 raw;
BitField<20, 19, u64> value;
@@ -44,6 +60,14 @@ IR::U32 TranslatorVisitor::GetImm(u64 insn) {
return ir.Imm32(value);
}
+IR::U32 TranslatorVisitor::GetImm32(u64 insn) {
+ union {
+ u64 raw;
+ BitField<20, 32, u64> value;
+ } const imm{insn};
+ return ir.Imm32(static_cast<u32>(imm.value));
+}
+
void TranslatorVisitor::SetZFlag(const IR::U1& value) {
ir.SetZFlag(value);
}
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h
index 8be7d6ff1..ef6d977fe 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h
@@ -46,7 +46,7 @@ public:
void DADD_reg(u64 insn);
void DADD_cbuf(u64 insn);
void DADD_imm(u64 insn);
- void DEPBAR(u64 insn);
+ void DEPBAR();
void DFMA_reg(u64 insn);
void DFMA_rc(u64 insn);
void DFMA_cr(u64 insn);
@@ -298,9 +298,14 @@ public:
[[nodiscard]] IR::U32 X(IR::Reg reg);
void X(IR::Reg dest_reg, const IR::U32& value);
+ [[nodiscard]] IR::U32 GetReg20(u64 insn);
+ [[nodiscard]] IR::U32 GetReg39(u64 insn);
+
[[nodiscard]] IR::U32 GetCbuf(u64 insn);
- [[nodiscard]] IR::U32 GetImm(u64 insn);
+ [[nodiscard]] IR::U32 GetImm20(u64 insn);
+
+ [[nodiscard]] IR::U32 GetImm32(u64 insn);
void SetZFlag(const IR::U1& value);
void SetSFlag(const IR::U1& value);
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/integer_add.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/integer_add.cpp
new file mode 100644
index 000000000..60f79b160
--- /dev/null
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/integer_add.cpp
@@ -0,0 +1,106 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/bit_field.h"
+#include "common/common_types.h"
+#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
+
+namespace Shader::Maxwell {
+namespace {
+void IADD(TranslatorVisitor& v, u64 insn, const IR::U32 op_b, bool neg_a, bool po, bool sat, bool x,
+ bool cc) {
+ union {
+ u64 raw;
+ BitField<0, 8, IR::Reg> dest_reg;
+ BitField<8, 8, IR::Reg> src_a;
+ } const iadd{insn};
+
+ if (sat) {
+ throw NotImplementedException("IADD SAT");
+ }
+ if (x && po) {
+ throw NotImplementedException("IADD X+PO");
+ }
+ // Operand A is always read from here, negated if needed
+ IR::U32 op_a{v.X(iadd.src_a)};
+ if (neg_a) {
+ op_a = v.ir.INeg(op_a);
+ }
+ // Add both operands
+ IR::U32 result{v.ir.IAdd(op_a, op_b)};
+ if (x) {
+ const IR::U32 carry{v.ir.Select(v.ir.GetCFlag(), v.ir.Imm32(1), v.ir.Imm32(0))};
+ result = v.ir.IAdd(result, carry);
+ }
+ if (po) {
+ // .PO adds one to the result
+ result = v.ir.IAdd(result, v.ir.Imm32(1));
+ }
+ if (cc) {
+ // Store flags
+ // TODO: Does this grab the result pre-PO or after?
+ if (po) {
+ throw NotImplementedException("IADD CC+PO");
+ }
+ // TODO: How does CC behave when X is set?
+ if (x) {
+ throw NotImplementedException("IADD X+CC");
+ }
+ v.SetZFlag(v.ir.GetZeroFromOp(result));
+ v.SetSFlag(v.ir.GetSignFromOp(result));
+ v.SetCFlag(v.ir.GetCarryFromOp(result));
+ v.SetOFlag(v.ir.GetOverflowFromOp(result));
+ }
+ // Store result
+ v.X(iadd.dest_reg, result);
+}
+
+void IADD(TranslatorVisitor& v, u64 insn, IR::U32 op_b) {
+ union {
+ u64 insn;
+ BitField<43, 1, u64> x;
+ BitField<47, 1, u64> cc;
+ BitField<48, 2, u64> three_for_po;
+ BitField<48, 1, u64> neg_b;
+ BitField<49, 1, u64> neg_a;
+ BitField<50, 1, u64> sat;
+ } const iadd{insn};
+
+ const bool po{iadd.three_for_po == 3};
+ const bool neg_a{!po && iadd.neg_a != 0};
+ if (!po && iadd.neg_b != 0) {
+ op_b = v.ir.INeg(op_b);
+ }
+ IADD(v, insn, op_b, iadd.neg_a != 0, po, iadd.sat != 0, iadd.x != 0, iadd.cc != 0);
+}
+} // Anonymous namespace
+
+void TranslatorVisitor::IADD_reg(u64) {
+ throw NotImplementedException("IADD (reg)");
+}
+
+void TranslatorVisitor::IADD_cbuf(u64 insn) {
+ IADD(*this, insn, GetCbuf(insn));
+}
+
+void TranslatorVisitor::IADD_imm(u64) {
+ throw NotImplementedException("IADD (imm)");
+}
+
+void TranslatorVisitor::IADD32I(u64 insn) {
+ union {
+ u64 raw;
+ BitField<52, 1, u64> cc;
+ BitField<53, 1, u64> x;
+ BitField<54, 1, u64> sat;
+ BitField<55, 2, u64> three_for_po;
+ BitField<56, 1, u64> neg_a;
+ } const iadd32i{insn};
+
+ const bool po{iadd32i.three_for_po == 3};
+ const bool neg_a{!po && iadd32i.neg_a != 0};
+ IADD(*this, insn, GetImm32(insn), neg_a, po, iadd32i.sat != 0, iadd32i.x != 0, iadd32i.cc != 0);
+}
+
+} // namespace Shader::Maxwell
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/integer_scaled_add.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/integer_scaled_add.cpp
new file mode 100644
index 000000000..f92c0bbd6
--- /dev/null
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/integer_scaled_add.cpp
@@ -0,0 +1,73 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/bit_field.h"
+#include "common/common_types.h"
+#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
+
+namespace Shader::Maxwell {
+namespace {
+void ISCADD(TranslatorVisitor& v, u64 insn, IR::U32 op_b) {
+ union {
+ u64 raw;
+ BitField<0, 8, IR::Reg> dest_reg;
+ BitField<8, 8, IR::Reg> op_a;
+ BitField<47, 1, u64> cc;
+ BitField<48, 2, u64> three_for_po;
+ BitField<48, 1, u64> neg_b;
+ BitField<49, 1, u64> neg_a;
+ BitField<39, 5, u64> scale;
+ } const iscadd{insn};
+
+ const bool po{iscadd.three_for_po == 3};
+ IR::U32 op_a{v.X(iscadd.op_a)};
+ if (!po) {
+ // When PO is not present, the bits are interpreted as negation
+ if (iscadd.neg_a != 0) {
+ op_a = v.ir.INeg(op_a);
+ }
+ if (iscadd.neg_b != 0) {
+ op_b = v.ir.INeg(op_b);
+ }
+ }
+ // With the operands already processed, scale A
+ const IR::U32 scale{v.ir.Imm32(static_cast<u32>(iscadd.scale))};
+ const IR::U32 scaled_a{v.ir.ShiftLeftLogical(op_a, scale)};
+
+ IR::U32 result{v.ir.IAdd(scaled_a, op_b)};
+ if (po) {
+ // .PO adds one to the final result
+ result = v.ir.IAdd(result, v.ir.Imm32(1));
+ }
+ v.X(iscadd.dest_reg, result);
+
+ if (iscadd.cc != 0) {
+ throw NotImplementedException("ISCADD CC");
+ }
+}
+
+} // Anonymous namespace
+
+void TranslatorVisitor::ISCADD_reg(u64 insn) {
+ union {
+ u64 raw;
+ BitField<20, 8, IR::Reg> op_b;
+ } const iscadd{insn};
+
+ ISCADD(*this, insn, X(iscadd.op_b));
+}
+
+void TranslatorVisitor::ISCADD_cbuf(u64) {
+ throw NotImplementedException("ISCADD (cbuf)");
+}
+
+void TranslatorVisitor::ISCADD_imm(u64) {
+ throw NotImplementedException("ISCADD (imm)");
+}
+
+void TranslatorVisitor::ISCADD32I(u64) {
+ throw NotImplementedException("ISCADD32I");
+}
+
+} // namespace Shader::Maxwell
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/integer_set_predicate.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/integer_set_predicate.cpp
new file mode 100644
index 000000000..76c6b5291
--- /dev/null
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/integer_set_predicate.cpp
@@ -0,0 +1,99 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/bit_field.h"
+#include "common/common_types.h"
+#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
+
+namespace Shader::Maxwell {
+namespace {
+enum class CompareOp : u64 {
+ F, // Always false
+ LT, // Less than
+ EQ, // Equal
+ LE, // Less than or equal
+ GT, // Greater than
+ NE, // Not equal
+ GE, // Greater than or equal
+ T, // Always true
+};
+
+enum class Bop : u64 {
+ AND,
+ OR,
+ XOR,
+};
+
+IR::U1 Compare(IR::IREmitter& ir, CompareOp op, const IR::U32& lhs, const IR::U32& rhs,
+ bool is_signed) {
+ switch (op) {
+ case CompareOp::F:
+ return ir.Imm1(false);
+ case CompareOp::LT:
+ return ir.ILessThan(lhs, rhs, is_signed);
+ case CompareOp::EQ:
+ return ir.IEqual(lhs, rhs);
+ case CompareOp::LE:
+ return ir.ILessThanEqual(lhs, rhs, is_signed);
+ case CompareOp::GT:
+ return ir.IGreaterThan(lhs, rhs, is_signed);
+ case CompareOp::NE:
+ return ir.INotEqual(lhs, rhs);
+ case CompareOp::GE:
+ return ir.IGreaterThanEqual(lhs, rhs, is_signed);
+ case CompareOp::T:
+ return ir.Imm1(true);
+ }
+ throw NotImplementedException("Invalid ISETP compare op {}", op);
+}
+
+IR::U1 Combine(IR::IREmitter& ir, Bop bop, const IR::U1& comparison, const IR::U1& bop_pred) {
+ switch (bop) {
+ case Bop::AND:
+ return ir.LogicalAnd(comparison, bop_pred);
+ case Bop::OR:
+ return ir.LogicalOr(comparison, bop_pred);
+ case Bop::XOR:
+ return ir.LogicalXor(comparison, bop_pred);
+ }
+ throw NotImplementedException("Invalid ISETP bop {}", bop);
+}
+
+void ISETP(TranslatorVisitor& v, u64 insn, const IR::U32& op_b) {
+ union {
+ u64 raw;
+ BitField<0, 3, IR::Pred> dest_pred_b;
+ BitField<3, 3, IR::Pred> dest_pred_a;
+ BitField<8, 8, IR::Reg> src_reg_a;
+ BitField<39, 3, IR::Pred> bop_pred;
+ BitField<42, 1, u64> neg_bop_pred;
+ BitField<45, 2, Bop> bop;
+ BitField<48, 1, u64> is_signed;
+ BitField<49, 3, CompareOp> compare_op;
+ } const isetp{insn};
+
+ const Bop bop{isetp.bop};
+ const IR::U32 op_a{v.X(isetp.src_reg_a)};
+ const IR::U1 comparison{Compare(v.ir, isetp.compare_op, op_a, op_b, isetp.is_signed != 0)};
+ const IR::U1 bop_pred{v.ir.GetPred(isetp.bop_pred, isetp.neg_bop_pred != 0)};
+ const IR::U1 result_a{Combine(v.ir, bop, comparison, bop_pred)};
+ const IR::U1 result_b{Combine(v.ir, bop, v.ir.LogicalNot(comparison), bop_pred)};
+ v.ir.SetPred(isetp.dest_pred_a, result_a);
+ v.ir.SetPred(isetp.dest_pred_b, result_b);
+}
+} // Anonymous namespace
+
+void TranslatorVisitor::ISETP_reg(u64 insn) {
+ ISETP(*this, insn, GetReg20(insn));
+}
+
+void TranslatorVisitor::ISETP_cbuf(u64 insn) {
+ ISETP(*this, insn, GetCbuf(insn));
+}
+
+void TranslatorVisitor::ISETP_imm(u64) {
+ throw NotImplementedException("ISETP_imm");
+}
+
+} // namespace Shader::Maxwell
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/integer_shift_left.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/integer_shift_left.cpp
new file mode 100644
index 000000000..d4b417d14
--- /dev/null
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/integer_shift_left.cpp
@@ -0,0 +1,71 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/bit_field.h"
+#include "common/common_types.h"
+#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
+
+namespace Shader::Maxwell {
+namespace {
+void SHL(TranslatorVisitor& v, u64 insn, const IR::U32& unsafe_shift) {
+ union {
+ u64 insn;
+ BitField<0, 8, IR::Reg> dest_reg;
+ BitField<8, 8, IR::Reg> src_reg_a;
+ BitField<39, 1, u64> w;
+ BitField<43, 1, u64> x;
+ BitField<47, 1, u64> cc;
+ } const shl{insn};
+
+ if (shl.x != 0) {
+ throw NotImplementedException("SHL.X");
+ }
+ if (shl.cc != 0) {
+ throw NotImplementedException("SHL.CC");
+ }
+ const IR::U32 base{v.X(shl.src_reg_a)};
+ IR::U32 result;
+ if (shl.w != 0) {
+ // When .W is set, the shift value is wrapped
+ // To emulate this we just have to clamp it ourselves.
+ const IR::U32 shift{v.ir.BitwiseAnd(unsafe_shift, v.ir.Imm32(31))};
+ result = v.ir.ShiftLeftLogical(base, shift);
+ } else {
+ // When .W is not set, the shift value is clamped between 0 and 32.
+ // To emulate this we have to have in mind the special shift of 32, that evaluates as 0.
+ // We can safely evaluate an out of bounds shift according to the SPIR-V specification:
+ //
+ // https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#OpShiftLeftLogical
+ // "Shift is treated as unsigned. The resulting value is undefined if Shift is greater than
+ // or equal to the bit width of the components of Base."
+ //
+ // And on the GLASM specification it is also safe to evaluate out of bounds:
+ //
+ // https://www.khronos.org/registry/OpenGL/extensions/NV/NV_gpu_program4.txt
+ // "The results of a shift operation ("<<") are undefined if the value of the second operand
+ // is negative, or greater than or equal to the number of bits in the first operand."
+ //
+ // Emphasis on undefined results in contrast to undefined behavior.
+ //
+ const IR::U1 is_safe{v.ir.ILessThan(unsafe_shift, v.ir.Imm32(32), false)};
+ const IR::U32 unsafe_result{v.ir.ShiftLeftLogical(base, unsafe_shift)};
+ result = v.ir.Select(is_safe, unsafe_result, v.ir.Imm32(0));
+ }
+ v.X(shl.dest_reg, result);
+}
+} // Anonymous namespace
+
+void TranslatorVisitor::SHL_reg(u64) {
+ throw NotImplementedException("SHL_reg");
+}
+
+void TranslatorVisitor::SHL_cbuf(u64) {
+ throw NotImplementedException("SHL_cbuf");
+}
+
+void TranslatorVisitor::SHL_imm(u64 insn) {
+ SHL(*this, insn, GetImm20(insn));
+}
+
+} // namespace Shader::Maxwell
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/integer_short_multiply_add.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/integer_short_multiply_add.cpp
new file mode 100644
index 000000000..70a7c76c5
--- /dev/null
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/integer_short_multiply_add.cpp
@@ -0,0 +1,110 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/bit_field.h"
+#include "common/common_types.h"
+#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
+
+namespace Shader::Maxwell {
+namespace {
+enum class SelectMode : u64 {
+ Default,
+ CLO,
+ CHI,
+ CSFU,
+ CBCC,
+};
+
+enum class Half : u64 {
+ H0, // Least-significant bits (15:0)
+ H1, // Most-significant bits (31:16)
+};
+
+IR::U32 ExtractHalf(TranslatorVisitor& v, const IR::U32& src, Half half, bool is_signed) {
+ const IR::U32 offset{v.ir.Imm32(half == Half::H1 ? 16 : 0)};
+ return v.ir.BitFieldExtract(src, offset, v.ir.Imm32(16), is_signed);
+}
+
+void XMAD(TranslatorVisitor& v, u64 insn, const IR::U32& src_b, const IR::U32& src_c,
+ SelectMode select_mode, Half half_b, bool psl, bool mrg, bool x) {
+ union {
+ u64 raw;
+ BitField<0, 8, IR::Reg> dest_reg;
+ BitField<8, 8, IR::Reg> src_reg_a;
+ BitField<47, 1, u64> cc;
+ BitField<48, 1, u64> is_a_signed;
+ BitField<49, 1, u64> is_b_signed;
+ BitField<53, 1, Half> half_a;
+ } const xmad{insn};
+
+ if (x) {
+ throw NotImplementedException("XMAD X");
+ }
+ const IR::U32 op_a{ExtractHalf(v, v.X(xmad.src_reg_a), xmad.half_a, xmad.is_a_signed != 0)};
+ const IR::U32 op_b{ExtractHalf(v, src_b, half_b, xmad.is_b_signed != 0)};
+
+ IR::U32 product{v.ir.IMul(op_a, op_b)};
+ if (psl) {
+ // .PSL shifts the product 16 bits
+ product = v.ir.ShiftLeftLogical(product, v.ir.Imm32(16));
+ }
+ const IR::U32 op_c{[&]() -> IR::U32 {
+ switch (select_mode) {
+ case SelectMode::Default:
+ return src_c;
+ case SelectMode::CLO:
+ return ExtractHalf(v, src_c, Half::H0, false);
+ case SelectMode::CHI:
+ return ExtractHalf(v, src_c, Half::H1, false);
+ case SelectMode::CBCC:
+ return v.ir.IAdd(v.ir.ShiftLeftLogical(src_b, v.ir.Imm32(16)), src_b);
+ case SelectMode::CSFU:
+ throw NotImplementedException("XMAD CSFU");
+ }
+ throw NotImplementedException("Invalid XMAD select mode {}", select_mode);
+ }()};
+ IR::U32 result{v.ir.IAdd(product, op_c)};
+ if (mrg) {
+ // .MRG inserts src_b [15:0] into result's [31:16].
+ const IR::U32 lsb_b{ExtractHalf(v, src_b, Half::H0, false)};
+ result = v.ir.BitFieldInsert(result, lsb_b, v.ir.Imm32(16), v.ir.Imm32(16));
+ }
+ if (xmad.cc) {
+ throw NotImplementedException("XMAD CC");
+ }
+ // Store result
+ v.X(xmad.dest_reg, result);
+}
+} // Anonymous namespace
+
+void TranslatorVisitor::XMAD_reg(u64) {
+ throw NotImplementedException("XMAD (reg)");
+}
+
+void TranslatorVisitor::XMAD_rc(u64) {
+ throw NotImplementedException("XMAD (rc)");
+}
+
+void TranslatorVisitor::XMAD_cr(u64) {
+ throw NotImplementedException("XMAD (cr)");
+}
+
+void TranslatorVisitor::XMAD_imm(u64 insn) {
+ union {
+ u64 raw;
+ BitField<20, 16, u64> src_b;
+ BitField<36, 1, u64> psl;
+ BitField<37, 1, u64> mrg;
+ BitField<38, 1, u64> x;
+ BitField<39, 8, IR::Reg> src_c;
+ BitField<50, 3, SelectMode> select_mode;
+ } const xmad{insn};
+
+ const IR::U32 src_b{ir.Imm32(static_cast<u32>(xmad.src_b))};
+ const IR::U32 src_c{X(xmad.src_c)};
+ XMAD(*this, insn, src_b, src_c, xmad.select_mode, Half::H0, xmad.psl != 0, xmad.mrg != 0,
+ xmad.x != 0);
+}
+
+} // namespace Shader::Maxwell
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_memory.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_memory.cpp
index d8fd387cf..c9669c617 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_memory.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_memory.cpp
@@ -10,16 +10,35 @@
namespace Shader::Maxwell {
namespace {
+enum class LoadSize : u64 {
+ U8, // Zero-extend
+ S8, // Sign-extend
+ U16, // Zero-extend
+ S16, // Sign-extend
+ B32,
+ B64,
+ B128,
+ U128, // ???
+};
+
enum class StoreSize : u64 {
- U8,
- S8,
- U16,
- S16,
+ U8, // Zero-extend
+ S8, // Sign-extend
+ U16, // Zero-extend
+ S16, // Sign-extend
B32,
B64,
B128,
};
+// See Table 27 in https://docs.nvidia.com/cuda/parallel-thread-execution/index.html
+enum class LoadCache : u64 {
+ CA, // Cache at all levels, likely to be accessed again
+ CG, // Cache at global level (cache in L2 and below, not L1)
+ CI, // ???
+ CV, // Don't cache and fetch again (consider cached system memory lines stale, fetch again)
+};
+
// See Table 28 in https://docs.nvidia.com/cuda/parallel-thread-execution/index.html
enum class StoreCache : u64 {
WB, // Cache write-back all coherent levels
@@ -27,61 +46,137 @@ enum class StoreCache : u64 {
CS, // Cache streaming, likely to be accessed once
WT, // Cache write-through (to system memory)
};
-} // Anonymous namespace
-void TranslatorVisitor::STG(u64 insn) {
- // STG stores registers into global memory.
+IR::U64 Address(TranslatorVisitor& v, u64 insn) {
union {
u64 raw;
- BitField<0, 8, IR::Reg> data_reg;
BitField<8, 8, IR::Reg> addr_reg;
+ BitField<20, 24, s64> addr_offset;
+ BitField<20, 24, u64> rz_addr_offset;
BitField<45, 1, u64> e;
- BitField<46, 2, StoreCache> cache;
- BitField<48, 3, StoreSize> size;
- } const stg{insn};
+ } const mem{insn};
const IR::U64 address{[&]() -> IR::U64 {
- if (stg.e == 0) {
- // STG without .E uses a 32-bit pointer, zero-extend it
- return ir.ConvertU(64, X(stg.addr_reg));
+ if (mem.e == 0) {
+ // LDG/STG without .E uses a 32-bit pointer, zero-extend it
+ return v.ir.ConvertU(64, v.X(mem.addr_reg));
}
- if (!IR::IsAligned(stg.addr_reg, 2)) {
+ if (!IR::IsAligned(mem.addr_reg, 2)) {
throw NotImplementedException("Unaligned address register");
}
- // Pack two registers to build the 32-bit address
- return ir.PackUint2x32(ir.CompositeConstruct(X(stg.addr_reg), X(stg.addr_reg + 1)));
+ // Pack two registers to build the 64-bit address
+ return v.ir.PackUint2x32(v.ir.CompositeConstruct(v.X(mem.addr_reg), v.X(mem.addr_reg + 1)));
+ }()};
+ const u64 addr_offset{[&]() -> u64 {
+ if (mem.addr_reg == IR::Reg::RZ) {
+ // When RZ is used, the address is an absolute address
+ return static_cast<u64>(mem.rz_addr_offset.Value());
+ } else {
+ return static_cast<u64>(mem.addr_offset.Value());
+ }
}()};
+ // Apply the offset
+ return v.ir.IAdd(address, v.ir.Imm64(addr_offset));
+}
+} // Anonymous namespace
+
+void TranslatorVisitor::LDG(u64 insn) {
+ // LDG loads global memory into registers
+ union {
+ u64 raw;
+ BitField<0, 8, IR::Reg> dest_reg;
+ BitField<46, 2, LoadCache> cache;
+ BitField<48, 3, LoadSize> size;
+ } const ldg{insn};
+
+ // Pointer to load data from
+ const IR::U64 address{Address(*this, insn)};
+ const IR::Reg dest_reg{ldg.dest_reg};
+ switch (ldg.size) {
+ case LoadSize::U8:
+ X(dest_reg, ir.LoadGlobalU8(address));
+ break;
+ case LoadSize::S8:
+ X(dest_reg, ir.LoadGlobalS8(address));
+ break;
+ case LoadSize::U16:
+ X(dest_reg, ir.LoadGlobalU16(address));
+ break;
+ case LoadSize::S16:
+ X(dest_reg, ir.LoadGlobalS16(address));
+ break;
+ case LoadSize::B32:
+ X(dest_reg, ir.LoadGlobal32(address));
+ break;
+ case LoadSize::B64: {
+ if (!IR::IsAligned(dest_reg, 2)) {
+ throw NotImplementedException("Unaligned data registers");
+ }
+ const IR::Value vector{ir.LoadGlobal64(address)};
+ for (int i = 0; i < 2; ++i) {
+ X(dest_reg + i, ir.CompositeExtract(vector, i));
+ }
+ break;
+ }
+ case LoadSize::B128: {
+ if (!IR::IsAligned(dest_reg, 4)) {
+ throw NotImplementedException("Unaligned data registers");
+ }
+ const IR::Value vector{ir.LoadGlobal128(address)};
+ for (int i = 0; i < 4; ++i) {
+ X(dest_reg + i, ir.CompositeExtract(vector, i));
+ }
+ break;
+ }
+ case LoadSize::U128:
+ throw NotImplementedException("LDG U.128");
+ default:
+ throw NotImplementedException("Invalid LDG size {}", ldg.size.Value());
+ }
+}
+
+void TranslatorVisitor::STG(u64 insn) {
+ // STG stores registers into global memory.
+ union {
+ u64 raw;
+ BitField<0, 8, IR::Reg> data_reg;
+ BitField<46, 2, StoreCache> cache;
+ BitField<48, 3, StoreSize> size;
+ } const stg{insn};
+ // Pointer to store data into
+ const IR::U64 address{Address(*this, insn)};
+ const IR::Reg data_reg{stg.data_reg};
switch (stg.size) {
case StoreSize::U8:
- ir.WriteGlobalU8(address, X(stg.data_reg));
+ ir.WriteGlobalU8(address, X(data_reg));
break;
case StoreSize::S8:
- ir.WriteGlobalS8(address, X(stg.data_reg));
+ ir.WriteGlobalS8(address, X(data_reg));
break;
case StoreSize::U16:
- ir.WriteGlobalU16(address, X(stg.data_reg));
+ ir.WriteGlobalU16(address, X(data_reg));
break;
case StoreSize::S16:
- ir.WriteGlobalS16(address, X(stg.data_reg));
+ ir.WriteGlobalS16(address, X(data_reg));
break;
case StoreSize::B32:
- ir.WriteGlobal32(address, X(stg.data_reg));
+ ir.WriteGlobal32(address, X(data_reg));
break;
case StoreSize::B64: {
- if (!IR::IsAligned(stg.data_reg, 2)) {
+ if (!IR::IsAligned(data_reg, 2)) {
throw NotImplementedException("Unaligned data registers");
}
- const IR::Value vector{ir.CompositeConstruct(X(stg.data_reg), X(stg.data_reg + 1))};
+ const IR::Value vector{ir.CompositeConstruct(X(data_reg), X(data_reg + 1))};
ir.WriteGlobal64(address, vector);
break;
}
case StoreSize::B128:
- if (!IR::IsAligned(stg.data_reg, 4)) {
+ if (!IR::IsAligned(data_reg, 4)) {
throw NotImplementedException("Unaligned data registers");
}
- const IR::Value vector{ir.CompositeConstruct(X(stg.data_reg), X(stg.data_reg + 1),
- X(stg.data_reg + 2), X(stg.data_reg + 3))};
+ const IR::Value vector{
+ ir.CompositeConstruct(X(data_reg), X(data_reg + 1), X(data_reg + 2), X(data_reg + 3))};
ir.WriteGlobal128(address, vector);
break;
}
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/register_move.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/move_register.cpp
index 7fa35ba3a..1711d3f48 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/register_move.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/move_register.cpp
@@ -39,7 +39,7 @@ void TranslatorVisitor::MOV_cbuf(u64 insn) {
void TranslatorVisitor::MOV_imm(u64 insn) {
const MOV mov{insn};
CheckMask(mov);
- X(mov.dest_reg, GetImm(insn));
+ X(mov.dest_reg, GetImm20(insn));
}
} // namespace Shader::Maxwell
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/move_special_register.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/move_special_register.cpp
new file mode 100644
index 000000000..93cea302a
--- /dev/null
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/move_special_register.cpp
@@ -0,0 +1,114 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/bit_field.h"
+#include "common/common_types.h"
+#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
+
+namespace Shader::Maxwell {
+namespace {
+enum class SpecialRegister : u64 {
+ SR_LANEID = 0,
+ SR_VIRTCFG = 2,
+ SR_VIRTID = 3,
+ SR_PM0 = 4,
+ SR_PM1 = 5,
+ SR_PM2 = 6,
+ SR_PM3 = 7,
+ SR_PM4 = 8,
+ SR_PM5 = 9,
+ SR_PM6 = 10,
+ SR_PM7 = 11,
+ SR_ORDERING_TICKET = 15,
+ SR_PRIM_TYPE = 16,
+ SR_INVOCATION_ID = 17,
+ SR_Y_DIRECTION = 18,
+ SR_THREAD_KILL = 19,
+ SM_SHADER_TYPE = 20,
+ SR_DIRECTCBEWRITEADDRESSLOW = 21,
+ SR_DIRECTCBEWRITEADDRESSHIGH = 22,
+ SR_DIRECTCBEWRITEENABLE = 23,
+ SR_MACHINE_ID_0 = 24,
+ SR_MACHINE_ID_1 = 25,
+ SR_MACHINE_ID_2 = 26,
+ SR_MACHINE_ID_3 = 27,
+ SR_AFFINITY = 28,
+ SR_INVOCATION_INFO = 29,
+ SR_WSCALEFACTOR_XY = 30,
+ SR_WSCALEFACTOR_Z = 31,
+ SR_TID = 32,
+ SR_TID_X = 33,
+ SR_TID_Y = 34,
+ SR_TID_Z = 35,
+ SR_CTAID_X = 37,
+ SR_CTAID_Y = 38,
+ SR_CTAID_Z = 39,
+ SR_NTID = 49,
+ SR_CirQueueIncrMinusOne = 50,
+ SR_NLATC = 51,
+ SR_SWINLO = 57,
+ SR_SWINSZ = 58,
+ SR_SMEMSZ = 59,
+ SR_SMEMBANKS = 60,
+ SR_LWINLO = 61,
+ SR_LWINSZ = 62,
+ SR_LMEMLOSZ = 63,
+ SR_LMEMHIOFF = 64,
+ SR_EQMASK = 65,
+ SR_LTMASK = 66,
+ SR_LEMASK = 67,
+ SR_GTMASK = 68,
+ SR_GEMASK = 69,
+ SR_REGALLOC = 70,
+ SR_GLOBALERRORSTATUS = 73,
+ SR_WARPERRORSTATUS = 75,
+ SR_PM_HI0 = 81,
+ SR_PM_HI1 = 82,
+ SR_PM_HI2 = 83,
+ SR_PM_HI3 = 84,
+ SR_PM_HI4 = 85,
+ SR_PM_HI5 = 86,
+ SR_PM_HI6 = 87,
+ SR_PM_HI7 = 88,
+ SR_CLOCKLO = 89,
+ SR_CLOCKHI = 90,
+ SR_GLOBALTIMERLO = 91,
+ SR_GLOBALTIMERHI = 92,
+ SR_HWTASKID = 105,
+ SR_CIRCULARQUEUEENTRYINDEX = 106,
+ SR_CIRCULARQUEUEENTRYADDRESSLOW = 107,
+ SR_CIRCULARQUEUEENTRYADDRESSHIGH = 108,
+};
+
+[[nodiscard]] IR::U32 Read(IR::IREmitter& ir, SpecialRegister special_register) {
+ switch (special_register) {
+ case SpecialRegister::SR_TID_X:
+ return ir.LocalInvocationIdX();
+ case SpecialRegister::SR_TID_Y:
+ return ir.LocalInvocationIdY();
+ case SpecialRegister::SR_TID_Z:
+ return ir.LocalInvocationIdZ();
+ case SpecialRegister::SR_CTAID_X:
+ return ir.WorkgroupIdX();
+ case SpecialRegister::SR_CTAID_Y:
+ return ir.WorkgroupIdY();
+ case SpecialRegister::SR_CTAID_Z:
+ return ir.WorkgroupIdZ();
+ default:
+ throw NotImplementedException("S2R special register {}", special_register);
+ }
+}
+} // Anonymous namespace
+
+void TranslatorVisitor::S2R(u64 insn) {
+ union {
+ u64 raw;
+ BitField<0, 8, IR::Reg> dest_reg;
+ BitField<20, 8, SpecialRegister> src_reg;
+ } const s2r{insn};
+
+ X(s2r.dest_reg, Read(ir, s2r.src_reg));
+}
+
+} // namespace Shader::Maxwell
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp
index 0f52696d1..d70399f6b 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp
@@ -7,21 +7,8 @@
#include "shader_recompiler/frontend/maxwell/opcode.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
-#include "shader_recompiler/ir_opt/passes.h"
-
namespace Shader::Maxwell {
-[[maybe_unused]] static inline void DumpOptimized(IR::Block& block) {
- auto raw{IR::DumpBlock(block)};
-
- Optimization::GetSetElimination(block);
- Optimization::DeadCodeEliminationPass(block);
- Optimization::IdentityRemovalPass(block);
- auto dumped{IR::DumpBlock(block)};
-
- fmt::print(stderr, "{}", dumped);
-}
-
[[noreturn]] static void ThrowNotImplemented(Opcode opcode) {
throw NotImplementedException("Instruction {} is not implemented", opcode);
}
@@ -146,8 +133,8 @@ void TranslatorVisitor::DADD_imm(u64) {
ThrowNotImplemented(Opcode::DADD_imm);
}
-void TranslatorVisitor::DEPBAR(u64) {
- ThrowNotImplemented(Opcode::DEPBAR);
+void TranslatorVisitor::DEPBAR() {
+ // DEPBAR is a no-op
}
void TranslatorVisitor::DFMA_reg(u64) {
@@ -230,22 +217,6 @@ void TranslatorVisitor::F2F_imm(u64) {
ThrowNotImplemented(Opcode::F2F_imm);
}
-void TranslatorVisitor::FADD_reg(u64) {
- ThrowNotImplemented(Opcode::FADD_reg);
-}
-
-void TranslatorVisitor::FADD_cbuf(u64) {
- ThrowNotImplemented(Opcode::FADD_cbuf);
-}
-
-void TranslatorVisitor::FADD_imm(u64) {
- ThrowNotImplemented(Opcode::FADD_imm);
-}
-
-void TranslatorVisitor::FADD32I(u64) {
- ThrowNotImplemented(Opcode::FADD32I);
-}
-
void TranslatorVisitor::FCHK_reg(u64) {
ThrowNotImplemented(Opcode::FCHK_reg);
}
@@ -274,26 +245,6 @@ void TranslatorVisitor::FCMP_imm(u64) {
ThrowNotImplemented(Opcode::FCMP_imm);
}
-void TranslatorVisitor::FFMA_reg(u64) {
- ThrowNotImplemented(Opcode::FFMA_reg);
-}
-
-void TranslatorVisitor::FFMA_rc(u64) {
- ThrowNotImplemented(Opcode::FFMA_rc);
-}
-
-void TranslatorVisitor::FFMA_cr(u64) {
- ThrowNotImplemented(Opcode::FFMA_cr);
-}
-
-void TranslatorVisitor::FFMA_imm(u64) {
- ThrowNotImplemented(Opcode::FFMA_imm);
-}
-
-void TranslatorVisitor::FFMA32I(u64) {
- ThrowNotImplemented(Opcode::FFMA32I);
-}
-
void TranslatorVisitor::FLO_reg(u64) {
ThrowNotImplemented(Opcode::FLO_reg);
}
@@ -318,22 +269,6 @@ void TranslatorVisitor::FMNMX_imm(u64) {
ThrowNotImplemented(Opcode::FMNMX_imm);
}
-void TranslatorVisitor::FMUL_reg(u64) {
- ThrowNotImplemented(Opcode::FMUL_reg);
-}
-
-void TranslatorVisitor::FMUL_cbuf(u64) {
- ThrowNotImplemented(Opcode::FMUL_cbuf);
-}
-
-void TranslatorVisitor::FMUL_imm(u64) {
- ThrowNotImplemented(Opcode::FMUL_imm);
-}
-
-void TranslatorVisitor::FMUL32I(u64) {
- ThrowNotImplemented(Opcode::FMUL32I);
-}
-
void TranslatorVisitor::FSET_reg(u64) {
ThrowNotImplemented(Opcode::FSET_reg);
}
@@ -470,18 +405,6 @@ void TranslatorVisitor::I2I_imm(u64) {
ThrowNotImplemented(Opcode::I2I_imm);
}
-void TranslatorVisitor::IADD_reg(u64) {
- ThrowNotImplemented(Opcode::IADD_reg);
-}
-
-void TranslatorVisitor::IADD_cbuf(u64) {
- ThrowNotImplemented(Opcode::IADD_cbuf);
-}
-
-void TranslatorVisitor::IADD_imm(u64) {
- ThrowNotImplemented(Opcode::IADD_imm);
-}
-
void TranslatorVisitor::IADD3_reg(u64) {
ThrowNotImplemented(Opcode::IADD3_reg);
}
@@ -494,10 +417,6 @@ void TranslatorVisitor::IADD3_imm(u64) {
ThrowNotImplemented(Opcode::IADD3_imm);
}
-void TranslatorVisitor::IADD32I(u64) {
- ThrowNotImplemented(Opcode::IADD32I);
-}
-
void TranslatorVisitor::ICMP_reg(u64) {
ThrowNotImplemented(Opcode::ICMP_reg);
}
@@ -594,22 +513,6 @@ void TranslatorVisitor::ISBERD(u64) {
ThrowNotImplemented(Opcode::ISBERD);
}
-void TranslatorVisitor::ISCADD_reg(u64) {
- ThrowNotImplemented(Opcode::ISCADD_reg);
-}
-
-void TranslatorVisitor::ISCADD_cbuf(u64) {
- ThrowNotImplemented(Opcode::ISCADD_cbuf);
-}
-
-void TranslatorVisitor::ISCADD_imm(u64) {
- ThrowNotImplemented(Opcode::ISCADD_imm);
-}
-
-void TranslatorVisitor::ISCADD32I(u64) {
- ThrowNotImplemented(Opcode::ISCADD32I);
-}
-
void TranslatorVisitor::ISET_reg(u64) {
ThrowNotImplemented(Opcode::ISET_reg);
}
@@ -622,18 +525,6 @@ void TranslatorVisitor::ISET_imm(u64) {
ThrowNotImplemented(Opcode::ISET_imm);
}
-void TranslatorVisitor::ISETP_reg(u64) {
- ThrowNotImplemented(Opcode::ISETP_reg);
-}
-
-void TranslatorVisitor::ISETP_cbuf(u64) {
- ThrowNotImplemented(Opcode::ISETP_cbuf);
-}
-
-void TranslatorVisitor::ISETP_imm(u64) {
- ThrowNotImplemented(Opcode::ISETP_imm);
-}
-
void TranslatorVisitor::JCAL(u64) {
ThrowNotImplemented(Opcode::JCAL);
}
@@ -658,10 +549,6 @@ void TranslatorVisitor::LDC(u64) {
ThrowNotImplemented(Opcode::LDC);
}
-void TranslatorVisitor::LDG(u64) {
- ThrowNotImplemented(Opcode::LDG);
-}
-
void TranslatorVisitor::LDL(u64) {
ThrowNotImplemented(Opcode::LDL);
}
@@ -866,10 +753,6 @@ void TranslatorVisitor::RTT(u64) {
ThrowNotImplemented(Opcode::RTT);
}
-void TranslatorVisitor::S2R(u64) {
- ThrowNotImplemented(Opcode::S2R);
-}
-
void TranslatorVisitor::SAM(u64) {
ThrowNotImplemented(Opcode::SAM);
}
@@ -914,18 +797,6 @@ void TranslatorVisitor::SHFL(u64) {
ThrowNotImplemented(Opcode::SHFL);
}
-void TranslatorVisitor::SHL_reg(u64) {
- ThrowNotImplemented(Opcode::SHL_reg);
-}
-
-void TranslatorVisitor::SHL_cbuf(u64) {
- ThrowNotImplemented(Opcode::SHL_cbuf);
-}
-
-void TranslatorVisitor::SHL_imm(u64) {
- ThrowNotImplemented(Opcode::SHL_imm);
-}
-
void TranslatorVisitor::SHR_reg(u64) {
ThrowNotImplemented(Opcode::SHR_reg);
}
@@ -1086,20 +957,4 @@ void TranslatorVisitor::VSHR(u64) {
ThrowNotImplemented(Opcode::VSHR);
}
-void TranslatorVisitor::XMAD_reg(u64) {
- ThrowNotImplemented(Opcode::XMAD_reg);
-}
-
-void TranslatorVisitor::XMAD_rc(u64) {
- ThrowNotImplemented(Opcode::XMAD_rc);
-}
-
-void TranslatorVisitor::XMAD_cr(u64) {
- ThrowNotImplemented(Opcode::XMAD_cr);
-}
-
-void TranslatorVisitor::XMAD_imm(u64) {
- ThrowNotImplemented(Opcode::XMAD_imm);
-}
-
} // namespace Shader::Maxwell