shader: Initial recompiler work
This commit is contained in:
parent
75059c46d6
commit
2d48a7b4d0
57 changed files with 7061 additions and 0 deletions
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
316
src/shader_recompiler/frontend/maxwell/translate/impl/impl.h
Normal file
316
src/shader_recompiler/frontend/maxwell/translate/impl/impl.h
Normal file
|
@ -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
|
|
@ -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
|
|
@ -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
|
File diff suppressed because it is too large
Load diff
|
@ -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
|
|
@ -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
|
16
src/shader_recompiler/frontend/maxwell/translate/translate.h
Normal file
16
src/shader_recompiler/frontend/maxwell/translate/translate.h
Normal file
|
@ -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
|
Loading…
Add table
Add a link
Reference in a new issue