summaryrefslogtreecommitdiffstats
path: root/src/shader_recompiler/frontend/maxwell/translate
diff options
context:
space:
mode:
authorReinUsesLisp <reinuseslisp@airmail.cc>2021-01-09 07:30:07 +0100
committerameerj <52414509+ameerj@users.noreply.github.com>2021-07-23 03:51:21 +0200
commit2d48a7b4d0666ad16d03a22d85712617a0849046 (patch)
treedd1069afca86f66e77e3438da77421a43adf5091 /src/shader_recompiler/frontend/maxwell/translate
parentthread_worker: Fix compile time error (diff)
downloadyuzu-2d48a7b4d0666ad16d03a22d85712617a0849046.tar
yuzu-2d48a7b4d0666ad16d03a22d85712617a0849046.tar.gz
yuzu-2d48a7b4d0666ad16d03a22d85712617a0849046.tar.bz2
yuzu-2d48a7b4d0666ad16d03a22d85712617a0849046.tar.lz
yuzu-2d48a7b4d0666ad16d03a22d85712617a0849046.tar.xz
yuzu-2d48a7b4d0666ad16d03a22d85712617a0849046.tar.zst
yuzu-2d48a7b4d0666ad16d03a22d85712617a0849046.zip
Diffstat (limited to '')
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/exit.cpp15
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp133
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_multi_function.cpp71
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp79
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/impl.h316
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/load_store_attribute.cpp92
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/load_store_memory.cpp90
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp1105
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/register_move.cpp45
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/translate.cpp50
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/translate.h16
11 files changed, 2012 insertions, 0 deletions
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/exit.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/exit.cpp
new file mode 100644
index 000000000..e98bbd0d1
--- /dev/null
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/exit.cpp
@@ -0,0 +1,15 @@
+// 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/impl.h"
+
+namespace Shader::Maxwell {
+
+void TranslatorVisitor::EXIT(u64) {
+ ir.Exit();
+}
+
+} // namespace Shader::Maxwell
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp
new file mode 100644
index 000000000..c4288d9a8
--- /dev/null
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp
@@ -0,0 +1,133 @@
+// 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/opcode.h"
+#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
+
+namespace Shader::Maxwell {
+namespace {
+enum class DestFormat : u64 {
+ Invalid,
+ I16,
+ I32,
+ I64,
+};
+enum class SrcFormat : u64 {
+ Invalid,
+ F16,
+ F32,
+ F64,
+};
+enum class Rounding : u64 {
+ Round,
+ Floor,
+ Ceil,
+ Trunc,
+};
+
+union F2I {
+ u64 raw;
+ BitField<0, 8, IR::Reg> dest_reg;
+ BitField<8, 2, DestFormat> dest_format;
+ BitField<10, 2, SrcFormat> src_format;
+ BitField<12, 1, u64> is_signed;
+ BitField<39, 1, Rounding> rounding;
+ BitField<49, 1, u64> half;
+ BitField<44, 1, u64> ftz;
+ BitField<45, 1, u64> abs;
+ BitField<47, 1, u64> cc;
+ BitField<49, 1, u64> neg;
+};
+
+size_t BitSize(DestFormat dest_format) {
+ switch (dest_format) {
+ case DestFormat::I16:
+ return 16;
+ case DestFormat::I32:
+ return 32;
+ case DestFormat::I64:
+ return 64;
+ default:
+ throw NotImplementedException("Invalid destination format {}", dest_format);
+ }
+}
+
+void TranslateF2I(TranslatorVisitor& v, u64 insn, const IR::U16U32U64& op_a) {
+ // F2I is used to convert from a floating point value to an integer
+ const F2I f2i{insn};
+
+ const IR::U16U32U64 float_value{v.ir.FPAbsNeg(op_a, f2i.abs != 0, f2i.neg != 0)};
+ const IR::U16U32U64 rounded_value{[&] {
+ switch (f2i.rounding) {
+ case Rounding::Round:
+ return v.ir.FPRoundEven(float_value);
+ case Rounding::Floor:
+ return v.ir.FPFloor(float_value);
+ case Rounding::Ceil:
+ return v.ir.FPCeil(float_value);
+ case Rounding::Trunc:
+ return v.ir.FPTrunc(float_value);
+ default:
+ throw NotImplementedException("Invalid F2I rounding {}", f2i.rounding.Value());
+ }
+ }()};
+
+ // TODO: Handle out of bounds conversions.
+ // For example converting F32 65537.0 to U16, the expected value is 0xffff,
+
+ const bool is_signed{f2i.is_signed != 0};
+ const size_t bitsize{BitSize(f2i.dest_format)};
+ const IR::U16U32U64 result{v.ir.ConvertFToI(bitsize, is_signed, rounded_value)};
+
+ v.X(f2i.dest_reg, result);
+
+ if (f2i.cc != 0) {
+ v.SetZFlag(v.ir.GetZeroFromOp(result));
+ if (is_signed) {
+ v.SetSFlag(v.ir.GetSignFromOp(result));
+ } else {
+ v.ResetSFlag();
+ }
+ v.ResetCFlag();
+
+ // TODO: Investigate if out of bound conversions sets the overflow flag
+ v.ResetOFlag();
+ }
+}
+} // Anonymous namespace
+
+void TranslatorVisitor::F2I_reg(u64 insn) {
+ union {
+ F2I base;
+ BitField<20, 8, IR::Reg> src_reg;
+ } const f2i{insn};
+
+ const IR::U16U32U64 op_a{[&]() -> IR::U16U32U64 {
+ switch (f2i.base.src_format) {
+ case SrcFormat::F16:
+ return ir.CompositeExtract(ir.UnpackFloat2x16(X(f2i.src_reg)), f2i.base.half);
+ case SrcFormat::F32:
+ return X(f2i.src_reg);
+ case SrcFormat::F64:
+ return ir.PackDouble2x32(ir.CompositeConstruct(X(f2i.src_reg), X(f2i.src_reg + 1)));
+ default:
+ throw NotImplementedException("Invalid F2I source format {}",
+ f2i.base.src_format.Value());
+ }
+ }()};
+
+ TranslateF2I(*this, insn, op_a);
+}
+
+void TranslatorVisitor::F2I_cbuf(u64) {
+ throw NotImplementedException("{}", Opcode::F2I_cbuf);
+}
+
+void TranslatorVisitor::F2I_imm(u64) {
+ throw NotImplementedException("{}", Opcode::F2I_imm);
+}
+
+} // namespace Shader::Maxwell
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_multi_function.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_multi_function.cpp
new file mode 100644
index 000000000..e2ab0dab2
--- /dev/null
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_multi_function.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/exception.h"
+#include "shader_recompiler/frontend/maxwell/opcode.h"
+#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
+
+namespace Shader::Maxwell {
+namespace {
+enum class Operation {
+ Cos = 0,
+ Sin = 1,
+ Ex2 = 2, // Base 2 exponent
+ Lg2 = 3, // Base 2 logarithm
+ Rcp = 4, // Reciprocal
+ Rsq = 5, // Reciprocal square root
+ Rcp64H = 6, // 64-bit reciprocal
+ Rsq64H = 7, // 64-bit reciprocal square root
+ Sqrt = 8,
+};
+} // Anonymous namespace
+
+void TranslatorVisitor::MUFU(u64 insn) {
+ // MUFU is used to implement a bunch of special functions. See Operation.
+ union {
+ u64 raw;
+ BitField<0, 8, IR::Reg> dest_reg;
+ BitField<8, 8, IR::Reg> src_reg;
+ BitField<20, 4, Operation> operation;
+ BitField<46, 1, u64> abs;
+ BitField<48, 1, u64> neg;
+ BitField<50, 1, u64> sat;
+ } const mufu{insn};
+
+ const IR::U32 op_a{ir.FPAbsNeg(X(mufu.src_reg), mufu.abs != 0, mufu.neg != 0)};
+ IR::U32 value{[&]() -> IR::U32 {
+ switch (mufu.operation) {
+ case Operation::Cos:
+ return ir.FPCosNotReduced(op_a);
+ case Operation::Sin:
+ return ir.FPSinNotReduced(op_a);
+ case Operation::Ex2:
+ return ir.FPExp2NotReduced(op_a);
+ case Operation::Lg2:
+ return ir.FPLog2(op_a);
+ case Operation::Rcp:
+ return ir.FPRecip(op_a);
+ case Operation::Rsq:
+ return ir.FPRecipSqrt(op_a);
+ case Operation::Rcp64H:
+ throw NotImplementedException("MUFU.RCP64H");
+ case Operation::Rsq64H:
+ throw NotImplementedException("MUFU.RSQ64H");
+ case Operation::Sqrt:
+ return ir.FPSqrt(op_a);
+ default:
+ throw NotImplementedException("Invalid MUFU operation {}", mufu.operation.Value());
+ }
+ }()};
+
+ if (mufu.sat) {
+ value = ir.FPSaturate(value);
+ }
+
+ X(mufu.dest_reg, value);
+}
+
+} // namespace Shader::Maxwell
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp
new file mode 100644
index 000000000..7bc7ce9f2
--- /dev/null
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp
@@ -0,0 +1,79 @@
+// 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 "shader_recompiler/frontend/ir/ir_emitter.h"
+#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
+
+namespace Shader::Maxwell {
+
+IR::U32 TranslatorVisitor::X(IR::Reg reg) {
+ return ir.GetReg(reg);
+}
+
+void TranslatorVisitor::X(IR::Reg dest_reg, const IR::U32& value) {
+ ir.SetReg(dest_reg, value);
+}
+
+IR::U32 TranslatorVisitor::GetCbuf(u64 insn) {
+ union {
+ u64 raw;
+ BitField<20, 14, s64> offset;
+ BitField<34, 5, u64> binding;
+ } const cbuf{insn};
+ if (cbuf.binding >= 18) {
+ throw NotImplementedException("Out of bounds constant buffer binding {}", cbuf.binding);
+ }
+ if (cbuf.offset >= 0x10'000 || cbuf.offset < 0) {
+ throw NotImplementedException("Out of bounds constant buffer offset {}", cbuf.offset);
+ }
+ const IR::U32 binding{ir.Imm32(static_cast<u32>(cbuf.binding))};
+ const IR::U32 byte_offset{ir.Imm32(static_cast<u32>(cbuf.offset) * 4)};
+ return ir.GetCbuf(binding, byte_offset);
+}
+
+IR::U32 TranslatorVisitor::GetImm(u64 insn) {
+ union {
+ u64 raw;
+ BitField<20, 19, u64> value;
+ BitField<56, 1, u64> is_negative;
+ } const imm{insn};
+ const s32 positive_value{static_cast<s32>(imm.value)};
+ const s32 value{imm.is_negative != 0 ? -positive_value : positive_value};
+ return ir.Imm32(value);
+}
+
+void TranslatorVisitor::SetZFlag(const IR::U1& value) {
+ ir.SetZFlag(value);
+}
+
+void TranslatorVisitor::SetSFlag(const IR::U1& value) {
+ ir.SetSFlag(value);
+}
+
+void TranslatorVisitor::SetCFlag(const IR::U1& value) {
+ ir.SetCFlag(value);
+}
+
+void TranslatorVisitor::SetOFlag(const IR::U1& value) {
+ ir.SetOFlag(value);
+}
+
+void TranslatorVisitor::ResetZero() {
+ SetZFlag(ir.Imm1(false));
+}
+
+void TranslatorVisitor::ResetSFlag() {
+ SetSFlag(ir.Imm1(false));
+}
+
+void TranslatorVisitor::ResetCFlag() {
+ SetCFlag(ir.Imm1(false));
+}
+
+void TranslatorVisitor::ResetOFlag() {
+ SetOFlag(ir.Imm1(false));
+}
+
+} // namespace Shader::Maxwell
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h
new file mode 100644
index 000000000..bc607b002
--- /dev/null
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h
@@ -0,0 +1,316 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "shader_recompiler/environment.h"
+#include "shader_recompiler/frontend/ir/basic_block.h"
+#include "shader_recompiler/frontend/ir/ir_emitter.h"
+#include "shader_recompiler/frontend/maxwell/instruction.h"
+
+namespace Shader::Maxwell {
+
+class TranslatorVisitor {
+public:
+ explicit TranslatorVisitor(Environment& env_, IR::Block& block) : env{env_} ,ir(block) {}
+
+ Environment& env;
+ IR::IREmitter ir;
+
+ void AL2P(u64 insn);
+ void ALD(u64 insn);
+ void AST(u64 insn);
+ void ATOM_cas(u64 insn);
+ void ATOM(u64 insn);
+ void ATOMS_cas(u64 insn);
+ void ATOMS(u64 insn);
+ void B2R(u64 insn);
+ void BAR(u64 insn);
+ void BFE_reg(u64 insn);
+ void BFE_cbuf(u64 insn);
+ void BFE_imm(u64 insn);
+ void BFI_reg(u64 insn);
+ void BFI_rc(u64 insn);
+ void BFI_cr(u64 insn);
+ void BFI_imm(u64 insn);
+ void BPT(u64 insn);
+ void BRA(u64 insn);
+ void BRK(u64 insn);
+ void BRX(u64 insn);
+ void CAL(u64 insn);
+ void CCTL(u64 insn);
+ void CCTLL(u64 insn);
+ void CONT(u64 insn);
+ void CS2R(u64 insn);
+ void CSET(u64 insn);
+ void CSETP(u64 insn);
+ void DADD_reg(u64 insn);
+ void DADD_cbuf(u64 insn);
+ void DADD_imm(u64 insn);
+ void DEPBAR(u64 insn);
+ void DFMA_reg(u64 insn);
+ void DFMA_rc(u64 insn);
+ void DFMA_cr(u64 insn);
+ void DFMA_imm(u64 insn);
+ void DMNMX_reg(u64 insn);
+ void DMNMX_cbuf(u64 insn);
+ void DMNMX_imm(u64 insn);
+ void DMUL_reg(u64 insn);
+ void DMUL_cbuf(u64 insn);
+ void DMUL_imm(u64 insn);
+ void DSET_reg(u64 insn);
+ void DSET_cbuf(u64 insn);
+ void DSET_imm(u64 insn);
+ void DSETP_reg(u64 insn);
+ void DSETP_cbuf(u64 insn);
+ void DSETP_imm(u64 insn);
+ void EXIT(u64 insn);
+ void F2F_reg(u64 insn);
+ void F2F_cbuf(u64 insn);
+ void F2F_imm(u64 insn);
+ void F2I_reg(u64 insn);
+ void F2I_cbuf(u64 insn);
+ void F2I_imm(u64 insn);
+ void FADD_reg(u64 insn);
+ void FADD_cbuf(u64 insn);
+ void FADD_imm(u64 insn);
+ void FADD32I(u64 insn);
+ void FCHK_reg(u64 insn);
+ void FCHK_cbuf(u64 insn);
+ void FCHK_imm(u64 insn);
+ void FCMP_reg(u64 insn);
+ void FCMP_rc(u64 insn);
+ void FCMP_cr(u64 insn);
+ void FCMP_imm(u64 insn);
+ void FFMA_reg(u64 insn);
+ void FFMA_rc(u64 insn);
+ void FFMA_cr(u64 insn);
+ void FFMA_imm(u64 insn);
+ void FFMA32I(u64 insn);
+ void FLO_reg(u64 insn);
+ void FLO_cbuf(u64 insn);
+ void FLO_imm(u64 insn);
+ void FMNMX_reg(u64 insn);
+ void FMNMX_cbuf(u64 insn);
+ void FMNMX_imm(u64 insn);
+ void FMUL_reg(u64 insn);
+ void FMUL_cbuf(u64 insn);
+ void FMUL_imm(u64 insn);
+ void FMUL32I(u64 insn);
+ void FSET_reg(u64 insn);
+ void FSET_cbuf(u64 insn);
+ void FSET_imm(u64 insn);
+ void FSETP_reg(u64 insn);
+ void FSETP_cbuf(u64 insn);
+ void FSETP_imm(u64 insn);
+ void FSWZADD(u64 insn);
+ void GETCRSPTR(u64 insn);
+ void GETLMEMBASE(u64 insn);
+ void HADD2_reg(u64 insn);
+ void HADD2_cbuf(u64 insn);
+ void HADD2_imm(u64 insn);
+ void HADD2_32I(u64 insn);
+ void HFMA2_reg(u64 insn);
+ void HFMA2_rc(u64 insn);
+ void HFMA2_cr(u64 insn);
+ void HFMA2_imm(u64 insn);
+ void HFMA2_32I(u64 insn);
+ void HMUL2_reg(u64 insn);
+ void HMUL2_cbuf(u64 insn);
+ void HMUL2_imm(u64 insn);
+ void HMUL2_32I(u64 insn);
+ void HSET2_reg(u64 insn);
+ void HSET2_cbuf(u64 insn);
+ void HSET2_imm(u64 insn);
+ void HSETP2_reg(u64 insn);
+ void HSETP2_cbuf(u64 insn);
+ void HSETP2_imm(u64 insn);
+ void I2F_reg(u64 insn);
+ void I2F_cbuf(u64 insn);
+ void I2F_imm(u64 insn);
+ void I2I_reg(u64 insn);
+ void I2I_cbuf(u64 insn);
+ void I2I_imm(u64 insn);
+ void IADD_reg(u64 insn);
+ void IADD_cbuf(u64 insn);
+ void IADD_imm(u64 insn);
+ void IADD3_reg(u64 insn);
+ void IADD3_cbuf(u64 insn);
+ void IADD3_imm(u64 insn);
+ void IADD32I(u64 insn);
+ void ICMP_reg(u64 insn);
+ void ICMP_rc(u64 insn);
+ void ICMP_cr(u64 insn);
+ void ICMP_imm(u64 insn);
+ void IDE(u64 insn);
+ void IDP_reg(u64 insn);
+ void IDP_imm(u64 insn);
+ void IMAD_reg(u64 insn);
+ void IMAD_rc(u64 insn);
+ void IMAD_cr(u64 insn);
+ void IMAD_imm(u64 insn);
+ void IMAD32I(u64 insn);
+ void IMADSP_reg(u64 insn);
+ void IMADSP_rc(u64 insn);
+ void IMADSP_cr(u64 insn);
+ void IMADSP_imm(u64 insn);
+ void IMNMX_reg(u64 insn);
+ void IMNMX_cbuf(u64 insn);
+ void IMNMX_imm(u64 insn);
+ void IMUL_reg(u64 insn);
+ void IMUL_cbuf(u64 insn);
+ void IMUL_imm(u64 insn);
+ void IMUL32I(u64 insn);
+ void IPA(u64 insn);
+ void ISBERD(u64 insn);
+ void ISCADD_reg(u64 insn);
+ void ISCADD_cbuf(u64 insn);
+ void ISCADD_imm(u64 insn);
+ void ISCADD32I(u64 insn);
+ void ISET_reg(u64 insn);
+ void ISET_cbuf(u64 insn);
+ void ISET_imm(u64 insn);
+ void ISETP_reg(u64 insn);
+ void ISETP_cbuf(u64 insn);
+ void ISETP_imm(u64 insn);
+ void JCAL(u64 insn);
+ void JMP(u64 insn);
+ void JMX(u64 insn);
+ void KIL(u64 insn);
+ void LD(u64 insn);
+ void LDC(u64 insn);
+ void LDG(u64 insn);
+ void LDL(u64 insn);
+ void LDS(u64 insn);
+ void LEA_hi_reg(u64 insn);
+ void LEA_hi_cbuf(u64 insn);
+ void LEA_lo_reg(u64 insn);
+ void LEA_lo_cbuf(u64 insn);
+ void LEA_lo_imm(u64 insn);
+ void LEPC(u64 insn);
+ void LONGJMP(u64 insn);
+ void LOP_reg(u64 insn);
+ void LOP_cbuf(u64 insn);
+ void LOP_imm(u64 insn);
+ void LOP3_reg(u64 insn);
+ void LOP3_cbuf(u64 insn);
+ void LOP3_imm(u64 insn);
+ void LOP32I(u64 insn);
+ void MEMBAR(u64 insn);
+ void MOV_reg(u64 insn);
+ void MOV_cbuf(u64 insn);
+ void MOV_imm(u64 insn);
+ void MOV32I(u64 insn);
+ void MUFU(u64 insn);
+ void NOP(u64 insn);
+ void OUT_reg(u64 insn);
+ void OUT_cbuf(u64 insn);
+ void OUT_imm(u64 insn);
+ void P2R_reg(u64 insn);
+ void P2R_cbuf(u64 insn);
+ void P2R_imm(u64 insn);
+ void PBK(u64 insn);
+ void PCNT(u64 insn);
+ void PEXIT(u64 insn);
+ void PIXLD(u64 insn);
+ void PLONGJMP(u64 insn);
+ void POPC_reg(u64 insn);
+ void POPC_cbuf(u64 insn);
+ void POPC_imm(u64 insn);
+ void PRET(u64 insn);
+ void PRMT_reg(u64 insn);
+ void PRMT_rc(u64 insn);
+ void PRMT_cr(u64 insn);
+ void PRMT_imm(u64 insn);
+ void PSET(u64 insn);
+ void PSETP(u64 insn);
+ void R2B(u64 insn);
+ void R2P_reg(u64 insn);
+ void R2P_cbuf(u64 insn);
+ void R2P_imm(u64 insn);
+ void RAM(u64 insn);
+ void RED(u64 insn);
+ void RET(u64 insn);
+ void RRO_reg(u64 insn);
+ void RRO_cbuf(u64 insn);
+ void RRO_imm(u64 insn);
+ void RTT(u64 insn);
+ void S2R(u64 insn);
+ void SAM(u64 insn);
+ void SEL_reg(u64 insn);
+ void SEL_cbuf(u64 insn);
+ void SEL_imm(u64 insn);
+ void SETCRSPTR(u64 insn);
+ void SETLMEMBASE(u64 insn);
+ void SHF_l_reg(u64 insn);
+ void SHF_l_imm(u64 insn);
+ void SHF_r_reg(u64 insn);
+ void SHF_r_imm(u64 insn);
+ void SHFL(u64 insn);
+ void SHL_reg(u64 insn);
+ void SHL_cbuf(u64 insn);
+ void SHL_imm(u64 insn);
+ void SHR_reg(u64 insn);
+ void SHR_cbuf(u64 insn);
+ void SHR_imm(u64 insn);
+ void SSY(u64 insn);
+ void ST(u64 insn);
+ void STG(u64 insn);
+ void STL(u64 insn);
+ void STP(u64 insn);
+ void STS(u64 insn);
+ void SUATOM_cas(u64 insn);
+ void SULD(u64 insn);
+ void SURED(u64 insn);
+ void SUST(u64 insn);
+ void SYNC(u64 insn);
+ void TEX(u64 insn);
+ void TEX_b(u64 insn);
+ void TEXS(u64 insn);
+ void TLD(u64 insn);
+ void TLD_b(u64 insn);
+ void TLD4(u64 insn);
+ void TLD4_b(u64 insn);
+ void TLD4S(u64 insn);
+ void TLDS(u64 insn);
+ void TMML(u64 insn);
+ void TMML_b(u64 insn);
+ void TXA(u64 insn);
+ void TXD(u64 insn);
+ void TXD_b(u64 insn);
+ void TXQ(u64 insn);
+ void TXQ_b(u64 insn);
+ void VABSDIFF(u64 insn);
+ void VABSDIFF4(u64 insn);
+ void VADD(u64 insn);
+ void VMAD(u64 insn);
+ void VMNMX(u64 insn);
+ void VOTE(u64 insn);
+ void VOTE_vtg(u64 insn);
+ void VSET(u64 insn);
+ void VSETP(u64 insn);
+ void VSHL(u64 insn);
+ void VSHR(u64 insn);
+ void XMAD_reg(u64 insn);
+ void XMAD_rc(u64 insn);
+ void XMAD_cr(u64 insn);
+ void XMAD_imm(u64 insn);
+
+ [[nodiscard]] IR::U32 X(IR::Reg reg);
+ void X(IR::Reg dest_reg, const IR::U32& value);
+
+ [[nodiscard]] IR::U32 GetCbuf(u64 insn);
+
+ [[nodiscard]] IR::U32 GetImm(u64 insn);
+
+ void SetZFlag(const IR::U1& value);
+ void SetSFlag(const IR::U1& value);
+ void SetCFlag(const IR::U1& value);
+ void SetOFlag(const IR::U1& value);
+
+ void ResetZero();
+ void ResetSFlag();
+ void ResetCFlag();
+ void ResetOFlag();
+};
+
+} // namespace Shader::Maxwell
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_attribute.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_attribute.cpp
new file mode 100644
index 000000000..23512db1a
--- /dev/null
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_attribute.cpp
@@ -0,0 +1,92 @@
+// 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/exception.h"
+#include "shader_recompiler/frontend/maxwell/opcode.h"
+#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
+
+namespace Shader::Maxwell {
+namespace {
+enum class InterpolationMode : u64 {
+ Pass = 0,
+ Multiply = 1,
+ Constant = 2,
+ Sc = 3,
+};
+
+enum class SampleMode : u64 {
+ Default = 0,
+ Centroid = 1,
+ Offset = 2,
+};
+} // Anonymous namespace
+
+void TranslatorVisitor::IPA(u64 insn) {
+ // IPA is the instruction used to read varyings from a fragment shader.
+ // gl_FragCoord is mapped to the gl_Position attribute.
+ // It yields unknown results when used outside of the fragment shader stage.
+ union {
+ u64 raw;
+ BitField<0, 8, IR::Reg> dest_reg;
+ BitField<8, 8, IR::Reg> index_reg;
+ BitField<20, 8, IR::Reg> multiplier;
+ BitField<30, 8, IR::Attribute> attribute;
+ BitField<38, 1, u64> idx;
+ BitField<51, 1, u64> sat;
+ BitField<52, 2, SampleMode> sample_mode;
+ BitField<54, 2, InterpolationMode> interpolation_mode;
+ } const ipa{insn};
+
+ // Indexed IPAs are used for indexed varyings.
+ // For example:
+ //
+ // in vec4 colors[4];
+ // uniform int idx;
+ // void main() {
+ // gl_FragColor = colors[idx];
+ // }
+ const bool is_indexed{ipa.idx != 0 && ipa.index_reg != IR::Reg::RZ};
+ if (is_indexed) {
+ throw NotImplementedException("IPA.IDX");
+ }
+
+ const IR::Attribute attribute{ipa.attribute};
+ IR::U32 value{ir.GetAttribute(attribute)};
+ if (IR::IsGeneric(attribute)) {
+ // const bool is_perspective{UnimplementedReadHeader(GenericAttributeIndex(attribute))};
+ const bool is_perspective{false};
+ if (is_perspective) {
+ const IR::U32 rcp_position_w{ir.FPRecip(ir.GetAttribute(IR::Attribute::PositionW))};
+ value = ir.FPMul(value, rcp_position_w);
+ }
+ }
+
+ switch (ipa.interpolation_mode) {
+ case InterpolationMode::Pass:
+ break;
+ case InterpolationMode::Multiply:
+ value = ir.FPMul(value, ir.GetReg(ipa.multiplier));
+ break;
+ case InterpolationMode::Constant:
+ throw NotImplementedException("IPA.CONSTANT");
+ case InterpolationMode::Sc:
+ throw NotImplementedException("IPA.SC");
+ }
+
+ // Saturated IPAs are generally generated out of clamped varyings.
+ // For example: clamp(some_varying, 0.0, 1.0)
+ const bool is_saturated{ipa.sat != 0};
+ if (is_saturated) {
+ if (attribute == IR::Attribute::FrontFace) {
+ throw NotImplementedException("IPA.SAT on FrontFace");
+ }
+ value = ir.FPSaturate(value);
+ }
+
+ ir.SetReg(ipa.dest_reg, value);
+}
+
+} // 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
new file mode 100644
index 000000000..d8fd387cf
--- /dev/null
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_memory.cpp
@@ -0,0 +1,90 @@
+// 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/exception.h"
+#include "shader_recompiler/frontend/maxwell/opcode.h"
+#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
+
+namespace Shader::Maxwell {
+namespace {
+enum class StoreSize : u64 {
+ U8,
+ S8,
+ U16,
+ S16,
+ B32,
+ B64,
+ B128,
+};
+
+// 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
+ CG, // Cache at global level
+ 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.
+ union {
+ u64 raw;
+ BitField<0, 8, IR::Reg> data_reg;
+ BitField<8, 8, IR::Reg> addr_reg;
+ BitField<45, 1, u64> e;
+ BitField<46, 2, StoreCache> cache;
+ BitField<48, 3, StoreSize> size;
+ } const stg{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 (!IR::IsAligned(stg.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)));
+ }()};
+
+ switch (stg.size) {
+ case StoreSize::U8:
+ ir.WriteGlobalU8(address, X(stg.data_reg));
+ break;
+ case StoreSize::S8:
+ ir.WriteGlobalS8(address, X(stg.data_reg));
+ break;
+ case StoreSize::U16:
+ ir.WriteGlobalU16(address, X(stg.data_reg));
+ break;
+ case StoreSize::S16:
+ ir.WriteGlobalS16(address, X(stg.data_reg));
+ break;
+ case StoreSize::B32:
+ ir.WriteGlobal32(address, X(stg.data_reg));
+ break;
+ case StoreSize::B64: {
+ if (!IR::IsAligned(stg.data_reg, 2)) {
+ throw NotImplementedException("Unaligned data registers");
+ }
+ const IR::Value vector{ir.CompositeConstruct(X(stg.data_reg), X(stg.data_reg + 1))};
+ ir.WriteGlobal64(address, vector);
+ break;
+ }
+ case StoreSize::B128:
+ if (!IR::IsAligned(stg.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))};
+ ir.WriteGlobal128(address, vector);
+ break;
+ }
+}
+
+} // 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
new file mode 100644
index 000000000..c907c1ffb
--- /dev/null
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp
@@ -0,0 +1,1105 @@
+// 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/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);
+}
+
+void TranslatorVisitor::AL2P(u64) {
+ ThrowNotImplemented(Opcode::AL2P);
+}
+
+void TranslatorVisitor::ALD(u64) {
+ ThrowNotImplemented(Opcode::ALD);
+}
+
+void TranslatorVisitor::AST(u64) {
+ ThrowNotImplemented(Opcode::AST);
+}
+
+void TranslatorVisitor::ATOM_cas(u64) {
+ ThrowNotImplemented(Opcode::ATOM_cas);
+}
+
+void TranslatorVisitor::ATOM(u64) {
+ ThrowNotImplemented(Opcode::ATOM);
+}
+
+void TranslatorVisitor::ATOMS_cas(u64) {
+ ThrowNotImplemented(Opcode::ATOMS_cas);
+}
+
+void TranslatorVisitor::ATOMS(u64) {
+ ThrowNotImplemented(Opcode::ATOMS);
+}
+
+void TranslatorVisitor::B2R(u64) {
+ ThrowNotImplemented(Opcode::B2R);
+}
+
+void TranslatorVisitor::BAR(u64) {
+ ThrowNotImplemented(Opcode::BAR);
+}
+
+void TranslatorVisitor::BFE_reg(u64) {
+ ThrowNotImplemented(Opcode::BFE_reg);
+}
+
+void TranslatorVisitor::BFE_cbuf(u64) {
+ ThrowNotImplemented(Opcode::BFE_cbuf);
+}
+
+void TranslatorVisitor::BFE_imm(u64) {
+ ThrowNotImplemented(Opcode::BFE_imm);
+}
+
+void TranslatorVisitor::BFI_reg(u64) {
+ ThrowNotImplemented(Opcode::BFI_reg);
+}
+
+void TranslatorVisitor::BFI_rc(u64) {
+ ThrowNotImplemented(Opcode::BFI_rc);
+}
+
+void TranslatorVisitor::BFI_cr(u64) {
+ ThrowNotImplemented(Opcode::BFI_cr);
+}
+
+void TranslatorVisitor::BFI_imm(u64) {
+ ThrowNotImplemented(Opcode::BFI_imm);
+}
+
+void TranslatorVisitor::BPT(u64) {
+ ThrowNotImplemented(Opcode::BPT);
+}
+
+void TranslatorVisitor::BRA(u64) {
+ ThrowNotImplemented(Opcode::BRA);
+}
+
+void TranslatorVisitor::BRK(u64) {
+ ThrowNotImplemented(Opcode::BRK);
+}
+
+void TranslatorVisitor::BRX(u64) {
+ ThrowNotImplemented(Opcode::BRX);
+}
+
+void TranslatorVisitor::CAL(u64) {
+ ThrowNotImplemented(Opcode::CAL);
+}
+
+void TranslatorVisitor::CCTL(u64) {
+ ThrowNotImplemented(Opcode::CCTL);
+}
+
+void TranslatorVisitor::CCTLL(u64) {
+ ThrowNotImplemented(Opcode::CCTLL);
+}
+
+void TranslatorVisitor::CONT(u64) {
+ ThrowNotImplemented(Opcode::CONT);
+}
+
+void TranslatorVisitor::CS2R(u64) {
+ ThrowNotImplemented(Opcode::CS2R);
+}
+
+void TranslatorVisitor::CSET(u64) {
+ ThrowNotImplemented(Opcode::CSET);
+}
+
+void TranslatorVisitor::CSETP(u64) {
+ ThrowNotImplemented(Opcode::CSETP);
+}
+
+void TranslatorVisitor::DADD_reg(u64) {
+ ThrowNotImplemented(Opcode::DADD_reg);
+}
+
+void TranslatorVisitor::DADD_cbuf(u64) {
+ ThrowNotImplemented(Opcode::DADD_cbuf);
+}
+
+void TranslatorVisitor::DADD_imm(u64) {
+ ThrowNotImplemented(Opcode::DADD_imm);
+}
+
+void TranslatorVisitor::DEPBAR(u64) {
+ ThrowNotImplemented(Opcode::DEPBAR);
+}
+
+void TranslatorVisitor::DFMA_reg(u64) {
+ ThrowNotImplemented(Opcode::DFMA_reg);
+}
+
+void TranslatorVisitor::DFMA_rc(u64) {
+ ThrowNotImplemented(Opcode::DFMA_rc);
+}
+
+void TranslatorVisitor::DFMA_cr(u64) {
+ ThrowNotImplemented(Opcode::DFMA_cr);
+}
+
+void TranslatorVisitor::DFMA_imm(u64) {
+ ThrowNotImplemented(Opcode::DFMA_imm);
+}
+
+void TranslatorVisitor::DMNMX_reg(u64) {
+ ThrowNotImplemented(Opcode::DMNMX_reg);
+}
+
+void TranslatorVisitor::DMNMX_cbuf(u64) {
+ ThrowNotImplemented(Opcode::DMNMX_cbuf);
+}
+
+void TranslatorVisitor::DMNMX_imm(u64) {
+ ThrowNotImplemented(Opcode::DMNMX_imm);
+}
+
+void TranslatorVisitor::DMUL_reg(u64) {
+ ThrowNotImplemented(Opcode::DMUL_reg);
+}
+
+void TranslatorVisitor::DMUL_cbuf(u64) {
+ ThrowNotImplemented(Opcode::DMUL_cbuf);
+}
+
+void TranslatorVisitor::DMUL_imm(u64) {
+ ThrowNotImplemented(Opcode::DMUL_imm);
+}
+
+void TranslatorVisitor::DSET_reg(u64) {
+ ThrowNotImplemented(Opcode::DSET_reg);
+}
+
+void TranslatorVisitor::DSET_cbuf(u64) {
+ ThrowNotImplemented(Opcode::DSET_cbuf);
+}
+
+void TranslatorVisitor::DSET_imm(u64) {
+ ThrowNotImplemented(Opcode::DSET_imm);
+}
+
+void TranslatorVisitor::DSETP_reg(u64) {
+ ThrowNotImplemented(Opcode::DSETP_reg);
+}
+
+void TranslatorVisitor::DSETP_cbuf(u64) {
+ ThrowNotImplemented(Opcode::DSETP_cbuf);
+}
+
+void TranslatorVisitor::DSETP_imm(u64) {
+ ThrowNotImplemented(Opcode::DSETP_imm);
+}
+
+void TranslatorVisitor::EXIT(u64) {
+ throw LogicError("Visting EXIT instruction");
+}
+
+void TranslatorVisitor::F2F_reg(u64) {
+ ThrowNotImplemented(Opcode::F2F_reg);
+}
+
+void TranslatorVisitor::F2F_cbuf(u64) {
+ ThrowNotImplemented(Opcode::F2F_cbuf);
+}
+
+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);
+}
+
+void TranslatorVisitor::FCHK_cbuf(u64) {
+ ThrowNotImplemented(Opcode::FCHK_cbuf);
+}
+
+void TranslatorVisitor::FCHK_imm(u64) {
+ ThrowNotImplemented(Opcode::FCHK_imm);
+}
+
+void TranslatorVisitor::FCMP_reg(u64) {
+ ThrowNotImplemented(Opcode::FCMP_reg);
+}
+
+void TranslatorVisitor::FCMP_rc(u64) {
+ ThrowNotImplemented(Opcode::FCMP_rc);
+}
+
+void TranslatorVisitor::FCMP_cr(u64) {
+ ThrowNotImplemented(Opcode::FCMP_cr);
+}
+
+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);
+}
+
+void TranslatorVisitor::FLO_cbuf(u64) {
+ ThrowNotImplemented(Opcode::FLO_cbuf);
+}
+
+void TranslatorVisitor::FLO_imm(u64) {
+ ThrowNotImplemented(Opcode::FLO_imm);
+}
+
+void TranslatorVisitor::FMNMX_reg(u64) {
+ ThrowNotImplemented(Opcode::FMNMX_reg);
+}
+
+void TranslatorVisitor::FMNMX_cbuf(u64) {
+ ThrowNotImplemented(Opcode::FMNMX_cbuf);
+}
+
+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);
+}
+
+void TranslatorVisitor::FSET_cbuf(u64) {
+ ThrowNotImplemented(Opcode::FSET_cbuf);
+}
+
+void TranslatorVisitor::FSET_imm(u64) {
+ ThrowNotImplemented(Opcode::FSET_imm);
+}
+
+void TranslatorVisitor::FSETP_reg(u64) {
+ ThrowNotImplemented(Opcode::FSETP_reg);
+}
+
+void TranslatorVisitor::FSETP_cbuf(u64) {
+ ThrowNotImplemented(Opcode::FSETP_cbuf);
+}
+
+void TranslatorVisitor::FSETP_imm(u64) {
+ ThrowNotImplemented(Opcode::FSETP_imm);
+}
+
+void TranslatorVisitor::FSWZADD(u64) {
+ ThrowNotImplemented(Opcode::FSWZADD);
+}
+
+void TranslatorVisitor::GETCRSPTR(u64) {
+ ThrowNotImplemented(Opcode::GETCRSPTR);
+}
+
+void TranslatorVisitor::GETLMEMBASE(u64) {
+ ThrowNotImplemented(Opcode::GETLMEMBASE);
+}
+
+void TranslatorVisitor::HADD2_reg(u64) {
+ ThrowNotImplemented(Opcode::HADD2_reg);
+}
+
+void TranslatorVisitor::HADD2_cbuf(u64) {
+ ThrowNotImplemented(Opcode::HADD2_cbuf);
+}
+
+void TranslatorVisitor::HADD2_imm(u64) {
+ ThrowNotImplemented(Opcode::HADD2_imm);
+}
+
+void TranslatorVisitor::HADD2_32I(u64) {
+ ThrowNotImplemented(Opcode::HADD2_32I);
+}
+
+void TranslatorVisitor::HFMA2_reg(u64) {
+ ThrowNotImplemented(Opcode::HFMA2_reg);
+}
+
+void TranslatorVisitor::HFMA2_rc(u64) {
+ ThrowNotImplemented(Opcode::HFMA2_rc);
+}
+
+void TranslatorVisitor::HFMA2_cr(u64) {
+ ThrowNotImplemented(Opcode::HFMA2_cr);
+}
+
+void TranslatorVisitor::HFMA2_imm(u64) {
+ ThrowNotImplemented(Opcode::HFMA2_imm);
+}
+
+void TranslatorVisitor::HFMA2_32I(u64) {
+ ThrowNotImplemented(Opcode::HFMA2_32I);
+}
+
+void TranslatorVisitor::HMUL2_reg(u64) {
+ ThrowNotImplemented(Opcode::HMUL2_reg);
+}
+
+void TranslatorVisitor::HMUL2_cbuf(u64) {
+ ThrowNotImplemented(Opcode::HMUL2_cbuf);
+}
+
+void TranslatorVisitor::HMUL2_imm(u64) {
+ ThrowNotImplemented(Opcode::HMUL2_imm);
+}
+
+void TranslatorVisitor::HMUL2_32I(u64) {
+ ThrowNotImplemented(Opcode::HMUL2_32I);
+}
+
+void TranslatorVisitor::HSET2_reg(u64) {
+ ThrowNotImplemented(Opcode::HSET2_reg);
+}
+
+void TranslatorVisitor::HSET2_cbuf(u64) {
+ ThrowNotImplemented(Opcode::HSET2_cbuf);
+}
+
+void TranslatorVisitor::HSET2_imm(u64) {
+ ThrowNotImplemented(Opcode::HSET2_imm);
+}
+
+void TranslatorVisitor::HSETP2_reg(u64) {
+ ThrowNotImplemented(Opcode::HSETP2_reg);
+}
+
+void TranslatorVisitor::HSETP2_cbuf(u64) {
+ ThrowNotImplemented(Opcode::HSETP2_cbuf);
+}
+
+void TranslatorVisitor::HSETP2_imm(u64) {
+ ThrowNotImplemented(Opcode::HSETP2_imm);
+}
+
+void TranslatorVisitor::I2F_reg(u64) {
+ ThrowNotImplemented(Opcode::I2F_reg);
+}
+
+void TranslatorVisitor::I2F_cbuf(u64) {
+ ThrowNotImplemented(Opcode::I2F_cbuf);
+}
+
+void TranslatorVisitor::I2F_imm(u64) {
+ ThrowNotImplemented(Opcode::I2F_imm);
+}
+
+void TranslatorVisitor::I2I_reg(u64) {
+ ThrowNotImplemented(Opcode::I2I_reg);
+}
+
+void TranslatorVisitor::I2I_cbuf(u64) {
+ ThrowNotImplemented(Opcode::I2I_cbuf);
+}
+
+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);
+}
+
+void TranslatorVisitor::IADD3_cbuf(u64) {
+ ThrowNotImplemented(Opcode::IADD3_cbuf);
+}
+
+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);
+}
+
+void TranslatorVisitor::ICMP_rc(u64) {
+ ThrowNotImplemented(Opcode::ICMP_rc);
+}
+
+void TranslatorVisitor::ICMP_cr(u64) {
+ ThrowNotImplemented(Opcode::ICMP_cr);
+}
+
+void TranslatorVisitor::ICMP_imm(u64) {
+ ThrowNotImplemented(Opcode::ICMP_imm);
+}
+
+void TranslatorVisitor::IDE(u64) {
+ ThrowNotImplemented(Opcode::IDE);
+}
+
+void TranslatorVisitor::IDP_reg(u64) {
+ ThrowNotImplemented(Opcode::IDP_reg);
+}
+
+void TranslatorVisitor::IDP_imm(u64) {
+ ThrowNotImplemented(Opcode::IDP_imm);
+}
+
+void TranslatorVisitor::IMAD_reg(u64) {
+ ThrowNotImplemented(Opcode::IMAD_reg);
+}
+
+void TranslatorVisitor::IMAD_rc(u64) {
+ ThrowNotImplemented(Opcode::IMAD_rc);
+}
+
+void TranslatorVisitor::IMAD_cr(u64) {
+ ThrowNotImplemented(Opcode::IMAD_cr);
+}
+
+void TranslatorVisitor::IMAD_imm(u64) {
+ ThrowNotImplemented(Opcode::IMAD_imm);
+}
+
+void TranslatorVisitor::IMAD32I(u64) {
+ ThrowNotImplemented(Opcode::IMAD32I);
+}
+
+void TranslatorVisitor::IMADSP_reg(u64) {
+ ThrowNotImplemented(Opcode::IMADSP_reg);
+}
+
+void TranslatorVisitor::IMADSP_rc(u64) {
+ ThrowNotImplemented(Opcode::IMADSP_rc);
+}
+
+void TranslatorVisitor::IMADSP_cr(u64) {
+ ThrowNotImplemented(Opcode::IMADSP_cr);
+}
+
+void TranslatorVisitor::IMADSP_imm(u64) {
+ ThrowNotImplemented(Opcode::IMADSP_imm);
+}
+
+void TranslatorVisitor::IMNMX_reg(u64) {
+ ThrowNotImplemented(Opcode::IMNMX_reg);
+}
+
+void TranslatorVisitor::IMNMX_cbuf(u64) {
+ ThrowNotImplemented(Opcode::IMNMX_cbuf);
+}
+
+void TranslatorVisitor::IMNMX_imm(u64) {
+ ThrowNotImplemented(Opcode::IMNMX_imm);
+}
+
+void TranslatorVisitor::IMUL_reg(u64) {
+ ThrowNotImplemented(Opcode::IMUL_reg);
+}
+
+void TranslatorVisitor::IMUL_cbuf(u64) {
+ ThrowNotImplemented(Opcode::IMUL_cbuf);
+}
+
+void TranslatorVisitor::IMUL_imm(u64) {
+ ThrowNotImplemented(Opcode::IMUL_imm);
+}
+
+void TranslatorVisitor::IMUL32I(u64) {
+ ThrowNotImplemented(Opcode::IMUL32I);
+}
+
+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);
+}
+
+void TranslatorVisitor::ISET_cbuf(u64) {
+ ThrowNotImplemented(Opcode::ISET_cbuf);
+}
+
+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);
+}
+
+void TranslatorVisitor::JMP(u64) {
+ ThrowNotImplemented(Opcode::JMP);
+}
+
+void TranslatorVisitor::JMX(u64) {
+ ThrowNotImplemented(Opcode::JMX);
+}
+
+void TranslatorVisitor::KIL(u64) {
+ ThrowNotImplemented(Opcode::KIL);
+}
+
+void TranslatorVisitor::LD(u64) {
+ ThrowNotImplemented(Opcode::LD);
+}
+
+void TranslatorVisitor::LDC(u64) {
+ ThrowNotImplemented(Opcode::LDC);
+}
+
+void TranslatorVisitor::LDG(u64) {
+ ThrowNotImplemented(Opcode::LDG);
+}
+
+void TranslatorVisitor::LDL(u64) {
+ ThrowNotImplemented(Opcode::LDL);
+}
+
+void TranslatorVisitor::LDS(u64) {
+ ThrowNotImplemented(Opcode::LDS);
+}
+
+void TranslatorVisitor::LEA_hi_reg(u64) {
+ ThrowNotImplemented(Opcode::LEA_hi_reg);
+}
+
+void TranslatorVisitor::LEA_hi_cbuf(u64) {
+ ThrowNotImplemented(Opcode::LEA_hi_cbuf);
+}
+
+void TranslatorVisitor::LEA_lo_reg(u64) {
+ ThrowNotImplemented(Opcode::LEA_lo_reg);
+}
+
+void TranslatorVisitor::LEA_lo_cbuf(u64) {
+ ThrowNotImplemented(Opcode::LEA_lo_cbuf);
+}
+
+void TranslatorVisitor::LEA_lo_imm(u64) {
+ ThrowNotImplemented(Opcode::LEA_lo_imm);
+}
+
+void TranslatorVisitor::LEPC(u64) {
+ ThrowNotImplemented(Opcode::LEPC);
+}
+
+void TranslatorVisitor::LONGJMP(u64) {
+ ThrowNotImplemented(Opcode::LONGJMP);
+}
+
+void TranslatorVisitor::LOP_reg(u64) {
+ ThrowNotImplemented(Opcode::LOP_reg);
+}
+
+void TranslatorVisitor::LOP_cbuf(u64) {
+ ThrowNotImplemented(Opcode::LOP_cbuf);
+}
+
+void TranslatorVisitor::LOP_imm(u64) {
+ ThrowNotImplemented(Opcode::LOP_imm);
+}
+
+void TranslatorVisitor::LOP3_reg(u64) {
+ ThrowNotImplemented(Opcode::LOP3_reg);
+}
+
+void TranslatorVisitor::LOP3_cbuf(u64) {
+ ThrowNotImplemented(Opcode::LOP3_cbuf);
+}
+
+void TranslatorVisitor::LOP3_imm(u64) {
+ ThrowNotImplemented(Opcode::LOP3_imm);
+}
+
+void TranslatorVisitor::LOP32I(u64) {
+ ThrowNotImplemented(Opcode::LOP32I);
+}
+
+void TranslatorVisitor::MEMBAR(u64) {
+ ThrowNotImplemented(Opcode::MEMBAR);
+}
+
+void TranslatorVisitor::MOV32I(u64) {
+ ThrowNotImplemented(Opcode::MOV32I);
+}
+
+void TranslatorVisitor::NOP(u64) {
+ ThrowNotImplemented(Opcode::NOP);
+}
+
+void TranslatorVisitor::OUT_reg(u64) {
+ ThrowNotImplemented(Opcode::OUT_reg);
+}
+
+void TranslatorVisitor::OUT_cbuf(u64) {
+ ThrowNotImplemented(Opcode::OUT_cbuf);
+}
+
+void TranslatorVisitor::OUT_imm(u64) {
+ ThrowNotImplemented(Opcode::OUT_imm);
+}
+
+void TranslatorVisitor::P2R_reg(u64) {
+ ThrowNotImplemented(Opcode::P2R_reg);
+}
+
+void TranslatorVisitor::P2R_cbuf(u64) {
+ ThrowNotImplemented(Opcode::P2R_cbuf);
+}
+
+void TranslatorVisitor::P2R_imm(u64) {
+ ThrowNotImplemented(Opcode::P2R_imm);
+}
+
+void TranslatorVisitor::PBK(u64) {
+ // PBK is a no-op
+}
+
+void TranslatorVisitor::PCNT(u64) {
+ ThrowNotImplemented(Opcode::PCNT);
+}
+
+void TranslatorVisitor::PEXIT(u64) {
+ ThrowNotImplemented(Opcode::PEXIT);
+}
+
+void TranslatorVisitor::PIXLD(u64) {
+ ThrowNotImplemented(Opcode::PIXLD);
+}
+
+void TranslatorVisitor::PLONGJMP(u64) {
+ ThrowNotImplemented(Opcode::PLONGJMP);
+}
+
+void TranslatorVisitor::POPC_reg(u64) {
+ ThrowNotImplemented(Opcode::POPC_reg);
+}
+
+void TranslatorVisitor::POPC_cbuf(u64) {
+ ThrowNotImplemented(Opcode::POPC_cbuf);
+}
+
+void TranslatorVisitor::POPC_imm(u64) {
+ ThrowNotImplemented(Opcode::POPC_imm);
+}
+
+void TranslatorVisitor::PRET(u64) {
+ ThrowNotImplemented(Opcode::PRET);
+}
+
+void TranslatorVisitor::PRMT_reg(u64) {
+ ThrowNotImplemented(Opcode::PRMT_reg);
+}
+
+void TranslatorVisitor::PRMT_rc(u64) {
+ ThrowNotImplemented(Opcode::PRMT_rc);
+}
+
+void TranslatorVisitor::PRMT_cr(u64) {
+ ThrowNotImplemented(Opcode::PRMT_cr);
+}
+
+void TranslatorVisitor::PRMT_imm(u64) {
+ ThrowNotImplemented(Opcode::PRMT_imm);
+}
+
+void TranslatorVisitor::PSET(u64) {
+ ThrowNotImplemented(Opcode::PSET);
+}
+
+void TranslatorVisitor::PSETP(u64) {
+ ThrowNotImplemented(Opcode::PSETP);
+}
+
+void TranslatorVisitor::R2B(u64) {
+ ThrowNotImplemented(Opcode::R2B);
+}
+
+void TranslatorVisitor::R2P_reg(u64) {
+ ThrowNotImplemented(Opcode::R2P_reg);
+}
+
+void TranslatorVisitor::R2P_cbuf(u64) {
+ ThrowNotImplemented(Opcode::R2P_cbuf);
+}
+
+void TranslatorVisitor::R2P_imm(u64) {
+ ThrowNotImplemented(Opcode::R2P_imm);
+}
+
+void TranslatorVisitor::RAM(u64) {
+ ThrowNotImplemented(Opcode::RAM);
+}
+
+void TranslatorVisitor::RED(u64) {
+ ThrowNotImplemented(Opcode::RED);
+}
+
+void TranslatorVisitor::RET(u64) {
+ ThrowNotImplemented(Opcode::RET);
+}
+
+void TranslatorVisitor::RRO_reg(u64) {
+ ThrowNotImplemented(Opcode::RRO_reg);
+}
+
+void TranslatorVisitor::RRO_cbuf(u64) {
+ ThrowNotImplemented(Opcode::RRO_cbuf);
+}
+
+void TranslatorVisitor::RRO_imm(u64) {
+ ThrowNotImplemented(Opcode::RRO_imm);
+}
+
+void TranslatorVisitor::RTT(u64) {
+ ThrowNotImplemented(Opcode::RTT);
+}
+
+void TranslatorVisitor::S2R(u64) {
+ ThrowNotImplemented(Opcode::S2R);
+}
+
+void TranslatorVisitor::SAM(u64) {
+ ThrowNotImplemented(Opcode::SAM);
+}
+
+void TranslatorVisitor::SEL_reg(u64) {
+ ThrowNotImplemented(Opcode::SEL_reg);
+}
+
+void TranslatorVisitor::SEL_cbuf(u64) {
+ ThrowNotImplemented(Opcode::SEL_cbuf);
+}
+
+void TranslatorVisitor::SEL_imm(u64) {
+ ThrowNotImplemented(Opcode::SEL_imm);
+}
+
+void TranslatorVisitor::SETCRSPTR(u64) {
+ ThrowNotImplemented(Opcode::SETCRSPTR);
+}
+
+void TranslatorVisitor::SETLMEMBASE(u64) {
+ ThrowNotImplemented(Opcode::SETLMEMBASE);
+}
+
+void TranslatorVisitor::SHF_l_reg(u64) {
+ ThrowNotImplemented(Opcode::SHF_l_reg);
+}
+
+void TranslatorVisitor::SHF_l_imm(u64) {
+ ThrowNotImplemented(Opcode::SHF_l_imm);
+}
+
+void TranslatorVisitor::SHF_r_reg(u64) {
+ ThrowNotImplemented(Opcode::SHF_r_reg);
+}
+
+void TranslatorVisitor::SHF_r_imm(u64) {
+ ThrowNotImplemented(Opcode::SHF_r_imm);
+}
+
+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);
+}
+
+void TranslatorVisitor::SHR_cbuf(u64) {
+ ThrowNotImplemented(Opcode::SHR_cbuf);
+}
+
+void TranslatorVisitor::SHR_imm(u64) {
+ ThrowNotImplemented(Opcode::SHR_imm);
+}
+
+void TranslatorVisitor::SSY(u64) {
+ ThrowNotImplemented(Opcode::SSY);
+}
+
+void TranslatorVisitor::ST(u64) {
+ ThrowNotImplemented(Opcode::ST);
+}
+
+void TranslatorVisitor::STL(u64) {
+ ThrowNotImplemented(Opcode::STL);
+}
+
+void TranslatorVisitor::STP(u64) {
+ ThrowNotImplemented(Opcode::STP);
+}
+
+void TranslatorVisitor::STS(u64) {
+ ThrowNotImplemented(Opcode::STS);
+}
+
+void TranslatorVisitor::SUATOM_cas(u64) {
+ ThrowNotImplemented(Opcode::SUATOM_cas);
+}
+
+void TranslatorVisitor::SULD(u64) {
+ ThrowNotImplemented(Opcode::SULD);
+}
+
+void TranslatorVisitor::SURED(u64) {
+ ThrowNotImplemented(Opcode::SURED);
+}
+
+void TranslatorVisitor::SUST(u64) {
+ ThrowNotImplemented(Opcode::SUST);
+}
+
+void TranslatorVisitor::SYNC(u64) {
+ ThrowNotImplemented(Opcode::SYNC);
+}
+
+void TranslatorVisitor::TEX(u64) {
+ ThrowNotImplemented(Opcode::TEX);
+}
+
+void TranslatorVisitor::TEX_b(u64) {
+ ThrowNotImplemented(Opcode::TEX_b);
+}
+
+void TranslatorVisitor::TEXS(u64) {
+ ThrowNotImplemented(Opcode::TEXS);
+}
+
+void TranslatorVisitor::TLD(u64) {
+ ThrowNotImplemented(Opcode::TLD);
+}
+
+void TranslatorVisitor::TLD_b(u64) {
+ ThrowNotImplemented(Opcode::TLD_b);
+}
+
+void TranslatorVisitor::TLD4(u64) {
+ ThrowNotImplemented(Opcode::TLD4);
+}
+
+void TranslatorVisitor::TLD4_b(u64) {
+ ThrowNotImplemented(Opcode::TLD4_b);
+}
+
+void TranslatorVisitor::TLD4S(u64) {
+ ThrowNotImplemented(Opcode::TLD4S);
+}
+
+void TranslatorVisitor::TLDS(u64) {
+ ThrowNotImplemented(Opcode::TLDS);
+}
+
+void TranslatorVisitor::TMML(u64) {
+ ThrowNotImplemented(Opcode::TMML);
+}
+
+void TranslatorVisitor::TMML_b(u64) {
+ ThrowNotImplemented(Opcode::TMML_b);
+}
+
+void TranslatorVisitor::TXA(u64) {
+ ThrowNotImplemented(Opcode::TXA);
+}
+
+void TranslatorVisitor::TXD(u64) {
+ ThrowNotImplemented(Opcode::TXD);
+}
+
+void TranslatorVisitor::TXD_b(u64) {
+ ThrowNotImplemented(Opcode::TXD_b);
+}
+
+void TranslatorVisitor::TXQ(u64) {
+ ThrowNotImplemented(Opcode::TXQ);
+}
+
+void TranslatorVisitor::TXQ_b(u64) {
+ ThrowNotImplemented(Opcode::TXQ_b);
+}
+
+void TranslatorVisitor::VABSDIFF(u64) {
+ ThrowNotImplemented(Opcode::VABSDIFF);
+}
+
+void TranslatorVisitor::VABSDIFF4(u64) {
+ ThrowNotImplemented(Opcode::VABSDIFF4);
+}
+
+void TranslatorVisitor::VADD(u64) {
+ ThrowNotImplemented(Opcode::VADD);
+}
+
+void TranslatorVisitor::VMAD(u64) {
+ ThrowNotImplemented(Opcode::VMAD);
+}
+
+void TranslatorVisitor::VMNMX(u64) {
+ ThrowNotImplemented(Opcode::VMNMX);
+}
+
+void TranslatorVisitor::VOTE(u64) {
+ ThrowNotImplemented(Opcode::VOTE);
+}
+
+void TranslatorVisitor::VOTE_vtg(u64) {
+ ThrowNotImplemented(Opcode::VOTE_vtg);
+}
+
+void TranslatorVisitor::VSET(u64) {
+ ThrowNotImplemented(Opcode::VSET);
+}
+
+void TranslatorVisitor::VSETP(u64) {
+ ThrowNotImplemented(Opcode::VSETP);
+}
+
+void TranslatorVisitor::VSHL(u64) {
+ ThrowNotImplemented(Opcode::VSHL);
+}
+
+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
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/register_move.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/register_move.cpp
new file mode 100644
index 000000000..7fa35ba3a
--- /dev/null
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/register_move.cpp
@@ -0,0 +1,45 @@
+// 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/exception.h"
+#include "shader_recompiler/frontend/maxwell/opcode.h"
+#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
+
+namespace Shader::Maxwell {
+namespace {
+union MOV {
+ u64 raw;
+ BitField<0, 8, IR::Reg> dest_reg;
+ BitField<20, 8, IR::Reg> src_reg;
+ BitField<39, 4, u64> mask;
+};
+
+void CheckMask(MOV mov) {
+ if (mov.mask != 0xf) {
+ throw NotImplementedException("Non-full move mask");
+ }
+}
+} // Anonymous namespace
+
+void TranslatorVisitor::MOV_reg(u64 insn) {
+ const MOV mov{insn};
+ CheckMask(mov);
+ X(mov.dest_reg, X(mov.src_reg));
+}
+
+void TranslatorVisitor::MOV_cbuf(u64 insn) {
+ const MOV mov{insn};
+ CheckMask(mov);
+ X(mov.dest_reg, GetCbuf(insn));
+}
+
+void TranslatorVisitor::MOV_imm(u64 insn) {
+ const MOV mov{insn};
+ CheckMask(mov);
+ X(mov.dest_reg, GetImm(insn));
+}
+
+} // namespace Shader::Maxwell
diff --git a/src/shader_recompiler/frontend/maxwell/translate/translate.cpp b/src/shader_recompiler/frontend/maxwell/translate/translate.cpp
new file mode 100644
index 000000000..66a306745
--- /dev/null
+++ b/src/shader_recompiler/frontend/maxwell/translate/translate.cpp
@@ -0,0 +1,50 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "shader_recompiler/environment.h"
+#include "shader_recompiler/frontend/ir/basic_block.h"
+#include "shader_recompiler/frontend/maxwell/decode.h"
+#include "shader_recompiler/frontend/maxwell/location.h"
+#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
+#include "shader_recompiler/frontend/maxwell/translate/translate.h"
+
+namespace Shader::Maxwell {
+
+template <auto visitor_method>
+static void Invoke(TranslatorVisitor& visitor, Location pc, u64 insn) {
+ using MethodType = decltype(visitor_method);
+ if constexpr (std::is_invocable_r_v<void, MethodType, TranslatorVisitor&, Location, u64>) {
+ (visitor.*visitor_method)(pc, insn);
+ } else if constexpr (std::is_invocable_r_v<void, MethodType, TranslatorVisitor&, u64>) {
+ (visitor.*visitor_method)(insn);
+ } else {
+ (visitor.*visitor_method)();
+ }
+}
+
+IR::Block Translate(Environment& env, const Flow::Block& flow_block) {
+ IR::Block block{flow_block.begin.Offset(), flow_block.end.Offset()};
+ TranslatorVisitor visitor{env, block};
+
+ const Location pc_end{flow_block.end};
+ Location pc{flow_block.begin};
+ while (pc != pc_end) {
+ const u64 insn{env.ReadInstruction(pc.Offset())};
+ const Opcode opcode{Decode(insn)};
+ switch (opcode) {
+#define INST(name, cute, mask) \
+ case Opcode::name: \
+ Invoke<&TranslatorVisitor::name>(visitor, pc, insn); \
+ break;
+#include "shader_recompiler/frontend/maxwell/maxwell.inc"
+#undef OPCODE
+ default:
+ throw LogicError("Invalid opcode {}", opcode);
+ }
+ ++pc;
+ }
+ return block;
+}
+
+} // namespace Shader::Maxwell
diff --git a/src/shader_recompiler/frontend/maxwell/translate/translate.h b/src/shader_recompiler/frontend/maxwell/translate/translate.h
new file mode 100644
index 000000000..788742dea
--- /dev/null
+++ b/src/shader_recompiler/frontend/maxwell/translate/translate.h
@@ -0,0 +1,16 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "shader_recompiler/environment.h"
+#include "shader_recompiler/frontend/ir/basic_block.h"
+#include "shader_recompiler/frontend/maxwell/location.h"
+#include "shader_recompiler/frontend/maxwell/control_flow.h"
+
+namespace Shader::Maxwell {
+
+[[nodiscard]] IR::Block Translate(Environment& env, const Flow::Block& flow_block);
+
+} // namespace Shader::Maxwell