mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-22 03:46:53 +02:00
refactor(graphics): split renderer and recompiler into focused modules
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
#include "graphics/shader/recompiler/decompiler/ExportOps.h"
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Decoder {
|
||||
|
||||
bool DecodeExp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error) {
|
||||
if (word_index + 1u >= code.size()) {
|
||||
if (error != nullptr) {
|
||||
*error = fmt::format("truncated EXP instruction at pc 0x{:08x}", pc);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32_t word0 = code[word_index];
|
||||
const uint32_t word1 = code[word_index + 1u];
|
||||
const uint32_t target = (word0 >> 4u) & 0x3fu;
|
||||
const uint32_t en = word0 & 0xfu;
|
||||
|
||||
inst.pc = pc;
|
||||
inst.word = word0;
|
||||
inst.word_count = 2;
|
||||
inst.family = Family::EXP;
|
||||
inst.opcode_id = target;
|
||||
inst.opcode = Opcode::Exp;
|
||||
inst.exp.target = target;
|
||||
inst.exp.en = en;
|
||||
inst.exp.compr = ((word0 >> 10u) & 1u) != 0;
|
||||
inst.exp.done = ((word0 >> 11u) & 1u) != 0;
|
||||
inst.exp.vm = ((word0 >> 12u) & 1u) != 0;
|
||||
SetRawWords(inst, code, word_index, 2);
|
||||
|
||||
if (!DecodeVectorGpr(word1 & 0xffu, inst.src0, error) ||
|
||||
!DecodeVectorGpr((word1 >> 8u) & 0xffu, inst.src1, error) ||
|
||||
!DecodeVectorGpr((word1 >> 16u) & 0xffu, inst.src2, error) ||
|
||||
!DecodeVectorGpr((word1 >> 24u) & 0xffu, inst.src3, error)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (target == 0x14u && inst.exp.done && en == 0x1u) {
|
||||
inst.src_count = 1u;
|
||||
} else {
|
||||
inst.src_count = inst.exp.compr ? 2u : 4u;
|
||||
}
|
||||
if (en == 0u) {
|
||||
inst.src_count = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Decoder
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_RECOMPILER_EXPORTOPS_H_
|
||||
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_RECOMPILER_EXPORTOPS_H_
|
||||
|
||||
#include "graphics/shader/recompiler/decompiler/ShaderDecoder.h"
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Decoder {
|
||||
|
||||
bool DecodeExp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error);
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Decoder
|
||||
|
||||
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_RECOMPILER_EXPORTOPS_H_ */
|
||||
@@ -0,0 +1,373 @@
|
||||
#include "graphics/shader/recompiler/decompiler/ImageOps.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <fmt/format.h>
|
||||
#include <iterator>
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Decoder {
|
||||
namespace {
|
||||
|
||||
struct MimgSampleInfo {
|
||||
uint32_t opcode = 0;
|
||||
const char* name = nullptr;
|
||||
uint32_t flags = 0;
|
||||
uint32_t address_components = 3;
|
||||
};
|
||||
|
||||
struct MimgGatherInfo {
|
||||
uint32_t opcode = 0;
|
||||
const char* name = nullptr;
|
||||
Opcode decoded = Opcode::Unsupported;
|
||||
uint32_t flags = 0;
|
||||
uint32_t address_components = 3;
|
||||
};
|
||||
|
||||
struct MimgAtomicInfo {
|
||||
uint32_t opcode = 0;
|
||||
const char* name = nullptr;
|
||||
Opcode decoded = Opcode::Unsupported;
|
||||
};
|
||||
|
||||
constexpr ImageDimension DecodeImageDimension(uint32_t dim) {
|
||||
switch (dim) {
|
||||
case 0u: return ImageDimension::Dim1D;
|
||||
case 1u: return ImageDimension::Dim2D;
|
||||
case 2u: return ImageDimension::Dim3D;
|
||||
case 3u: return ImageDimension::Dim2DArray;
|
||||
case 4u: return ImageDimension::Dim1DArray;
|
||||
case 5u:
|
||||
case 7u: return ImageDimension::Dim2DArray;
|
||||
case 6u: return ImageDimension::Dim2D;
|
||||
default: return ImageDimension::Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr uint32_t ImageCoordComponents(ImageDimension dimension) {
|
||||
switch (dimension) {
|
||||
case ImageDimension::Dim1D: return 1u;
|
||||
case ImageDimension::Dim1DArray: return 2u;
|
||||
case ImageDimension::Dim3D:
|
||||
case ImageDimension::Dim2DArray: return 3u;
|
||||
default: return 2u;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr uint32_t ImageGradientComponents(ImageDimension dimension) {
|
||||
switch (dimension) {
|
||||
case ImageDimension::Dim1D:
|
||||
case ImageDimension::Dim1DArray: return 1u;
|
||||
case ImageDimension::Dim3D: return 3u;
|
||||
default: return 2u;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr uint32_t ImageSampleAddressComponents(uint32_t flags, ImageDimension dimension) {
|
||||
const auto coord_components = ImageCoordComponents(dimension);
|
||||
uint32_t components = coord_components;
|
||||
if ((flags & ImageSampleFlagOffset) != 0) {
|
||||
components++;
|
||||
}
|
||||
if ((flags & ImageSampleFlagCompare) != 0) {
|
||||
components++;
|
||||
}
|
||||
if ((flags & ImageSampleFlagBias) != 0) {
|
||||
components++;
|
||||
}
|
||||
if ((flags & ImageSampleFlagLod) != 0) {
|
||||
components++;
|
||||
}
|
||||
if ((flags & ImageSampleFlagDerivative) != 0) {
|
||||
components += ImageGradientComponents(dimension) * 2u;
|
||||
}
|
||||
return components;
|
||||
}
|
||||
|
||||
constexpr MimgSampleInfo SampleInfo(uint32_t opcode, const char* name, uint32_t flags) {
|
||||
return {opcode, name, flags, ImageSampleAddressComponents(flags, ImageDimension::Dim2D)};
|
||||
}
|
||||
|
||||
constexpr MimgSampleInfo MIMG_SAMPLE_OPS[] = {
|
||||
SampleInfo(0x20u, "image_sample", 0),
|
||||
SampleInfo(0x21u, "image_sample_cl", ImageSampleFlagLodClamp),
|
||||
SampleInfo(0x22u, "image_sample_d", ImageSampleFlagDerivative),
|
||||
SampleInfo(0x23u, "image_sample_d_cl", ImageSampleFlagDerivative | ImageSampleFlagLodClamp),
|
||||
SampleInfo(0x24u, "image_sample_l", ImageSampleFlagLod),
|
||||
SampleInfo(0x25u, "image_sample_b", ImageSampleFlagBias),
|
||||
SampleInfo(0x26u, "image_sample_b_cl", ImageSampleFlagBias | ImageSampleFlagLodClamp),
|
||||
SampleInfo(0x27u, "image_sample_lz", ImageSampleFlagLevelZero),
|
||||
SampleInfo(0x28u, "image_sample_c", ImageSampleFlagCompare),
|
||||
SampleInfo(0x29u, "image_sample_c_cl", ImageSampleFlagCompare | ImageSampleFlagLodClamp),
|
||||
SampleInfo(0x2au, "image_sample_c_d", ImageSampleFlagCompare | ImageSampleFlagDerivative),
|
||||
SampleInfo(0x2bu, "image_sample_c_d_cl",
|
||||
ImageSampleFlagCompare | ImageSampleFlagDerivative | ImageSampleFlagLodClamp),
|
||||
SampleInfo(0x2cu, "image_sample_c_l", ImageSampleFlagCompare | ImageSampleFlagLod),
|
||||
SampleInfo(0x2du, "image_sample_c_b", ImageSampleFlagCompare | ImageSampleFlagBias),
|
||||
SampleInfo(0x2eu, "image_sample_c_b_cl",
|
||||
ImageSampleFlagCompare | ImageSampleFlagBias | ImageSampleFlagLodClamp),
|
||||
SampleInfo(0x2fu, "image_sample_c_lz", ImageSampleFlagCompare | ImageSampleFlagLevelZero),
|
||||
SampleInfo(0x30u, "image_sample_o", ImageSampleFlagOffset),
|
||||
SampleInfo(0x31u, "image_sample_cl_o", ImageSampleFlagLodClamp | ImageSampleFlagOffset),
|
||||
SampleInfo(0x32u, "image_sample_d_o", ImageSampleFlagDerivative | ImageSampleFlagOffset),
|
||||
SampleInfo(0x33u, "image_sample_d_cl_o",
|
||||
ImageSampleFlagDerivative | ImageSampleFlagLodClamp | ImageSampleFlagOffset),
|
||||
SampleInfo(0x34u, "image_sample_l_o", ImageSampleFlagLod | ImageSampleFlagOffset),
|
||||
SampleInfo(0x35u, "image_sample_b_o", ImageSampleFlagBias | ImageSampleFlagOffset),
|
||||
SampleInfo(0x36u, "image_sample_b_cl_o",
|
||||
ImageSampleFlagBias | ImageSampleFlagLodClamp | ImageSampleFlagOffset),
|
||||
SampleInfo(0x37u, "image_sample_lz_o", ImageSampleFlagLevelZero | ImageSampleFlagOffset),
|
||||
SampleInfo(0x38u, "image_sample_c_o", ImageSampleFlagCompare | ImageSampleFlagOffset),
|
||||
SampleInfo(0x39u, "image_sample_c_cl_o",
|
||||
ImageSampleFlagCompare | ImageSampleFlagLodClamp | ImageSampleFlagOffset),
|
||||
SampleInfo(0x3au, "image_sample_c_d_o",
|
||||
ImageSampleFlagCompare | ImageSampleFlagDerivative | ImageSampleFlagOffset),
|
||||
SampleInfo(0x3bu, "image_sample_c_d_cl_o",
|
||||
ImageSampleFlagCompare | ImageSampleFlagDerivative | ImageSampleFlagLodClamp |
|
||||
ImageSampleFlagOffset),
|
||||
SampleInfo(0x3cu, "image_sample_c_l_o",
|
||||
ImageSampleFlagCompare | ImageSampleFlagLod | ImageSampleFlagOffset),
|
||||
SampleInfo(0x3du, "image_sample_c_b_o",
|
||||
ImageSampleFlagCompare | ImageSampleFlagBias | ImageSampleFlagOffset),
|
||||
SampleInfo(0x3eu, "image_sample_c_b_cl_o",
|
||||
ImageSampleFlagCompare | ImageSampleFlagBias | ImageSampleFlagLodClamp |
|
||||
ImageSampleFlagOffset),
|
||||
SampleInfo(0x3fu, "image_sample_c_lz_o",
|
||||
ImageSampleFlagCompare | ImageSampleFlagLevelZero | ImageSampleFlagOffset),
|
||||
SampleInfo(0x68u, "image_sample_cd", ImageSampleFlagDerivative | ImageSampleFlagCd),
|
||||
SampleInfo(0x69u, "image_sample_cd_cl",
|
||||
ImageSampleFlagDerivative | ImageSampleFlagCd | ImageSampleFlagLodClamp),
|
||||
SampleInfo(0x6au, "image_sample_c_cd",
|
||||
ImageSampleFlagCompare | ImageSampleFlagDerivative | ImageSampleFlagCd),
|
||||
SampleInfo(0x6bu, "image_sample_c_cd_cl",
|
||||
ImageSampleFlagCompare | ImageSampleFlagDerivative | ImageSampleFlagCd |
|
||||
ImageSampleFlagLodClamp),
|
||||
SampleInfo(0x6cu, "image_sample_cd_o",
|
||||
ImageSampleFlagDerivative | ImageSampleFlagCd | ImageSampleFlagOffset),
|
||||
SampleInfo(0x6du, "image_sample_cd_cl_o",
|
||||
ImageSampleFlagDerivative | ImageSampleFlagCd | ImageSampleFlagLodClamp |
|
||||
ImageSampleFlagOffset),
|
||||
SampleInfo(0x6eu, "image_sample_c_cd_o",
|
||||
ImageSampleFlagCompare | ImageSampleFlagDerivative | ImageSampleFlagCd |
|
||||
ImageSampleFlagOffset),
|
||||
SampleInfo(0x6fu, "image_sample_c_cd_cl_o",
|
||||
ImageSampleFlagCompare | ImageSampleFlagDerivative | ImageSampleFlagCd |
|
||||
ImageSampleFlagLodClamp | ImageSampleFlagOffset),
|
||||
SampleInfo(0xa0u, "image_sample_a", 0),
|
||||
SampleInfo(0xa1u, "image_sample_cl_a", ImageSampleFlagLodClamp),
|
||||
SampleInfo(0xa5u, "image_sample_b_a", ImageSampleFlagBias),
|
||||
SampleInfo(0xa6u, "image_sample_b_cl_a", ImageSampleFlagBias | ImageSampleFlagLodClamp),
|
||||
SampleInfo(0xa8u, "image_sample_c_a", ImageSampleFlagCompare),
|
||||
SampleInfo(0xa9u, "image_sample_c_cl_a", ImageSampleFlagCompare | ImageSampleFlagLodClamp),
|
||||
SampleInfo(0xadu, "image_sample_c_b_a", ImageSampleFlagCompare | ImageSampleFlagBias),
|
||||
SampleInfo(0xaeu, "image_sample_c_b_cl_a",
|
||||
ImageSampleFlagCompare | ImageSampleFlagBias | ImageSampleFlagLodClamp),
|
||||
SampleInfo(0xb0u, "image_sample_o_a", ImageSampleFlagOffset),
|
||||
SampleInfo(0xb1u, "image_sample_cl_o_a", ImageSampleFlagLodClamp | ImageSampleFlagOffset),
|
||||
SampleInfo(0xb5u, "image_sample_b_o_a", ImageSampleFlagBias | ImageSampleFlagOffset),
|
||||
SampleInfo(0xb6u, "image_sample_b_cl_o_a",
|
||||
ImageSampleFlagBias | ImageSampleFlagLodClamp | ImageSampleFlagOffset),
|
||||
SampleInfo(0xb8u, "image_sample_c_o_a", ImageSampleFlagCompare | ImageSampleFlagOffset),
|
||||
SampleInfo(0xb9u, "image_sample_c_cl_o_a",
|
||||
ImageSampleFlagCompare | ImageSampleFlagLodClamp | ImageSampleFlagOffset),
|
||||
SampleInfo(0xbdu, "image_sample_c_b_o_a",
|
||||
ImageSampleFlagCompare | ImageSampleFlagBias | ImageSampleFlagOffset),
|
||||
SampleInfo(0xbeu, "image_sample_c_b_cl_o_a",
|
||||
ImageSampleFlagCompare | ImageSampleFlagBias | ImageSampleFlagLodClamp |
|
||||
ImageSampleFlagOffset),
|
||||
};
|
||||
|
||||
constexpr MimgGatherInfo MIMG_GATHER_OPS[] = {
|
||||
{0x47u, "image_gather4_lz", Opcode::ImageGather4Lz, ImageSampleFlagLevelZero, 2u},
|
||||
{0x48u, "image_gather4_c", Opcode::ImageGather4C, ImageSampleFlagCompare, 3u},
|
||||
{0x4fu, "image_gather4_c_lz", Opcode::ImageGather4CLz,
|
||||
ImageSampleFlagCompare | ImageSampleFlagLevelZero, 3u},
|
||||
{0x57u, "image_gather4_lz_o", Opcode::ImageGather4LzO,
|
||||
ImageSampleFlagLevelZero | ImageSampleFlagOffset, 3u},
|
||||
{0x58u, "image_gather4_c_o", Opcode::ImageGather4CO,
|
||||
ImageSampleFlagCompare | ImageSampleFlagOffset, 4u},
|
||||
{0x5fu, "image_gather4_c_lz_o", Opcode::ImageGather4CLzO,
|
||||
ImageSampleFlagCompare | ImageSampleFlagLevelZero | ImageSampleFlagOffset, 4u},
|
||||
{0x61u, "image_gather4h", Opcode::ImageGather4H, ImageSampleFlagGatherHorizontal, 2u},
|
||||
};
|
||||
|
||||
constexpr MimgAtomicInfo MIMG_ATOMIC_OPS[] = {
|
||||
{0x11u, "image_atomic_add", Opcode::ImageAtomicAdd},
|
||||
{0x15u, "image_atomic_umin", Opcode::ImageAtomicUMin},
|
||||
{0x17u, "image_atomic_umax", Opcode::ImageAtomicUMax},
|
||||
{0x18u, "image_atomic_and", Opcode::ImageAtomicAnd},
|
||||
{0x19u, "image_atomic_or", Opcode::ImageAtomicOr},
|
||||
{0x1au, "image_atomic_xor", Opcode::ImageAtomicXor},
|
||||
};
|
||||
|
||||
const MimgSampleInfo* LookupSample(uint32_t opcode) {
|
||||
for (const auto& info: MIMG_SAMPLE_OPS) {
|
||||
if (info.opcode == opcode) {
|
||||
return &info;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const MimgGatherInfo* LookupGather(uint32_t opcode) {
|
||||
for (const auto& info: MIMG_GATHER_OPS) {
|
||||
if (info.opcode == opcode) {
|
||||
return &info;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const MimgAtomicInfo* LookupAtomic(uint32_t opcode) {
|
||||
for (const auto& info: MIMG_ATOMIC_OPS) {
|
||||
if (info.opcode == opcode) {
|
||||
return &info;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Opcode DecodeMimgOpcode(uint32_t opcode, const MimgSampleInfo* sample, const MimgGatherInfo* gather,
|
||||
const MimgAtomicInfo* atomic) {
|
||||
if (sample != nullptr) {
|
||||
return Opcode::ImageSample;
|
||||
}
|
||||
if (gather != nullptr) {
|
||||
return gather->decoded;
|
||||
}
|
||||
if (atomic != nullptr) {
|
||||
return atomic->decoded;
|
||||
}
|
||||
|
||||
switch (opcode) {
|
||||
case 0x00u: return Opcode::ImageLoad;
|
||||
case 0x01u: return Opcode::ImageLoadMip;
|
||||
case 0x08u: return Opcode::ImageStore;
|
||||
case 0x09u: return Opcode::ImageStoreMip;
|
||||
case 0x0eu: return Opcode::ImageGetResinfo;
|
||||
case 0x60u: return Opcode::ImageGetLod;
|
||||
default: return Opcode::Unsupported;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t DecodeMimgSampleFlags(const MimgSampleInfo* sample, const MimgGatherInfo* gather) {
|
||||
if (sample != nullptr) {
|
||||
return sample->flags;
|
||||
}
|
||||
if (gather != nullptr) {
|
||||
return gather->flags;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t DecodeMimgAddressComponents(uint32_t opcode, ImageDimension dimension,
|
||||
const MimgSampleInfo* sample, const MimgGatherInfo* gather,
|
||||
const MimgAtomicInfo* atomic) {
|
||||
if (sample != nullptr) {
|
||||
return ImageSampleAddressComponents(sample->flags, dimension);
|
||||
}
|
||||
if (gather != nullptr) {
|
||||
return ImageSampleAddressComponents(gather->flags, dimension);
|
||||
}
|
||||
if (atomic != nullptr) {
|
||||
return ImageCoordComponents(dimension);
|
||||
}
|
||||
|
||||
switch (opcode) {
|
||||
case 0x01u:
|
||||
case 0x09u: return ImageCoordComponents(dimension) + 1u;
|
||||
case 0x00u:
|
||||
case 0x08u:
|
||||
case 0x60u: return ImageCoordComponents(dimension);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t CountDmaskComponents(uint32_t dmask) {
|
||||
uint32_t count = 0;
|
||||
for (uint32_t i = 0; i < 4u; i++) {
|
||||
count += (dmask >> i) & 1u;
|
||||
}
|
||||
return count != 0 ? count : 1u;
|
||||
}
|
||||
|
||||
bool IsSingleDmaskBit(uint32_t dmask) {
|
||||
return dmask != 0u && (dmask & (dmask - 1u)) == 0u;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool DecodeMimg(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error) {
|
||||
if (word_index + 1u >= code.size()) {
|
||||
if (error != nullptr) {
|
||||
*error = fmt::format("truncated MIMG instruction at pc 0x{:08x}", pc);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32_t word0 = code[word_index];
|
||||
const uint32_t word1 = code[word_index + 1u];
|
||||
const uint32_t opcode = ((word0 >> 18u) & 0x7fu) | ((word0 & 1u) << 7u);
|
||||
const uint32_t nsa_dwords = (word0 >> 1u) & 0x3u;
|
||||
const auto dimension = DecodeImageDimension((word0 >> 3u) & 0x7u);
|
||||
const uint32_t word_count = 2u + nsa_dwords;
|
||||
if (word_index + word_count > code.size()) {
|
||||
if (error != nullptr) {
|
||||
*error = fmt::format("truncated MIMG NSA instruction at pc 0x{:08x}", pc);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32_t vdata = (word1 >> 8u) & 0xffu;
|
||||
const uint32_t vaddr = word1 & 0xffu;
|
||||
const uint32_t srsrc = (word1 >> 16u) & 0x1fu;
|
||||
const uint32_t ssamp = (word1 >> 21u) & 0x1fu;
|
||||
const bool a16 = ((word1 >> 30u) & 0x1u) != 0u;
|
||||
const auto* sample = LookupSample(opcode);
|
||||
const auto* gather = LookupGather(opcode);
|
||||
const auto* atomic = LookupAtomic(opcode);
|
||||
|
||||
inst.pc = pc;
|
||||
inst.word = word0;
|
||||
inst.word_count = word_count;
|
||||
inst.family = Family::MIMG;
|
||||
inst.opcode_id = opcode;
|
||||
inst.opcode = DecodeMimgOpcode(opcode, sample, gather, atomic);
|
||||
inst.dmask = (word0 >> 8u) & 0xfu;
|
||||
inst.data_dwords = gather != nullptr ? 4u : CountDmaskComponents(inst.dmask);
|
||||
inst.glc = ((word0 >> 13u) & 1u) != 0;
|
||||
inst.slc = ((word0 >> 25u) & 1u) != 0;
|
||||
inst.image_sample_flags = DecodeMimgSampleFlags(sample, gather);
|
||||
if (a16) {
|
||||
inst.image_sample_flags |= ImageSampleFlagA16;
|
||||
}
|
||||
inst.image_dimension = dimension;
|
||||
inst.image_nsa_dwords = nsa_dwords;
|
||||
for (uint32_t i = 0; i < nsa_dwords * 4u && i < MaxImageNsaAddressComponents; i++) {
|
||||
inst.image_nsa_addr[i] = (code[word_index + 2u + i / 4u] >> ((i % 4u) * 8u)) & 0xffu;
|
||||
}
|
||||
inst.image_address_components =
|
||||
DecodeMimgAddressComponents(opcode, dimension, sample, gather, atomic);
|
||||
SetRawWords(inst, code, word_index, word_count);
|
||||
|
||||
if (inst.opcode == Opcode::Unsupported) {
|
||||
SetUnsupported(inst, Family::MIMG, opcode, "MIMG opcode is not implemented");
|
||||
}
|
||||
if (gather != nullptr && !IsSingleDmaskBit(inst.dmask)) {
|
||||
SetUnsupported(inst, Family::MIMG, opcode,
|
||||
"MIMG image gather requires exactly one dmask bit");
|
||||
}
|
||||
|
||||
DecodeVectorGpr(vdata, inst.dst, nullptr);
|
||||
DecodeVectorGpr(vaddr, inst.src0, nullptr);
|
||||
DecodeScalarSource(srsrc * 4u, pc, inst.src1, nullptr);
|
||||
DecodeScalarSource(ssamp * 4u, pc, inst.src2, nullptr);
|
||||
inst.src_count = 3;
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* MimgSampleOpcodeName(uint32_t opcode) {
|
||||
const auto* sample = LookupSample(opcode);
|
||||
return sample != nullptr ? sample->name : nullptr;
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Decoder
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_RECOMPILER_IMAGEOPS_H_
|
||||
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_RECOMPILER_IMAGEOPS_H_
|
||||
|
||||
#include "graphics/shader/recompiler/decompiler/ShaderDecoder.h"
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Decoder {
|
||||
|
||||
bool DecodeMimg(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error);
|
||||
|
||||
const char* MimgSampleOpcodeName(uint32_t opcode);
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Decoder
|
||||
|
||||
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_RECOMPILER_IMAGEOPS_H_ */
|
||||
@@ -0,0 +1,480 @@
|
||||
#include "graphics/shader/recompiler/decompiler/MemoryOps.h"
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <iterator>
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Decoder {
|
||||
namespace {
|
||||
|
||||
struct MemoryOpcodeInfo {
|
||||
uint32_t opcode = 0;
|
||||
Opcode decoded = Opcode::Unsupported;
|
||||
uint32_t data_dwords = 1;
|
||||
uint32_t data_bits = 32;
|
||||
bool data_signed = false;
|
||||
bool typed = false;
|
||||
bool formatted = false;
|
||||
};
|
||||
|
||||
constexpr MemoryOpcodeInfo SMEM_OPS[] = {
|
||||
{0x00u, Opcode::SLoadDword, 1, 32}, {0x01u, Opcode::SLoadDwordx2, 2, 32},
|
||||
{0x02u, Opcode::SLoadDwordx4, 4, 32}, {0x03u, Opcode::SLoadDwordx8, 8, 32},
|
||||
{0x04u, Opcode::SLoadDwordx16, 16, 32}, {0x08u, Opcode::SBufferLoadDword, 1, 32},
|
||||
{0x09u, Opcode::SBufferLoadDwordx2, 2, 32}, {0x0au, Opcode::SBufferLoadDwordx4, 4, 32},
|
||||
{0x0bu, Opcode::SBufferLoadDwordx8, 8, 32}, {0x0cu, Opcode::SBufferLoadDwordx16, 16, 32},
|
||||
};
|
||||
|
||||
constexpr MemoryOpcodeInfo MUBUF_OPS[] = {
|
||||
{0x00u, Opcode::BufferLoadFormatX, 1, 32, false, false, true},
|
||||
{0x01u, Opcode::BufferLoadFormatXy, 2, 32, false, false, true},
|
||||
{0x02u, Opcode::BufferLoadFormatXyz, 3, 32, false, false, true},
|
||||
{0x03u, Opcode::BufferLoadFormatXyzw, 4, 32, false, false, true},
|
||||
{0x04u, Opcode::BufferStoreFormatX, 1, 32, false, false, true},
|
||||
{0x05u, Opcode::BufferStoreFormatXy, 2, 32, false, false, true},
|
||||
{0x06u, Opcode::BufferStoreFormatXyz, 3, 32, false, false, true},
|
||||
{0x07u, Opcode::BufferStoreFormatXyzw, 4, 32, false, false, true},
|
||||
{0x08u, Opcode::BufferLoadUbyte, 1, 8},
|
||||
{0x09u, Opcode::BufferLoadSbyte, 1, 8, true},
|
||||
{0x0au, Opcode::BufferLoadUshort, 1, 16},
|
||||
{0x0bu, Opcode::BufferLoadSshort, 1, 16, true},
|
||||
{0x0cu, Opcode::BufferLoadDword, 1, 32},
|
||||
{0x0du, Opcode::BufferLoadDwordx2, 2, 32},
|
||||
{0x0eu, Opcode::BufferLoadDwordx4, 4, 32},
|
||||
{0x0fu, Opcode::BufferLoadDwordx3, 3, 32},
|
||||
{0x18u, Opcode::BufferStoreByte, 1, 8},
|
||||
{0x1au, Opcode::BufferStoreShort, 1, 16},
|
||||
{0x1cu, Opcode::BufferStoreDword, 1, 32},
|
||||
{0x1du, Opcode::BufferStoreDwordx2, 2, 32},
|
||||
{0x1eu, Opcode::BufferStoreDwordx4, 4, 32},
|
||||
{0x1fu, Opcode::BufferStoreDwordx3, 3, 32},
|
||||
{0x30u, Opcode::BufferAtomicSwap, 1, 32},
|
||||
{0x32u, Opcode::BufferAtomicAdd, 1, 32},
|
||||
{0x33u, Opcode::BufferAtomicSub, 1, 32},
|
||||
{0x35u, Opcode::BufferAtomicSMin, 1, 32},
|
||||
{0x36u, Opcode::BufferAtomicUMin, 1, 32},
|
||||
{0x37u, Opcode::BufferAtomicSMax, 1, 32},
|
||||
{0x38u, Opcode::BufferAtomicUMax, 1, 32},
|
||||
{0x39u, Opcode::BufferAtomicAnd, 1, 32},
|
||||
{0x3au, Opcode::BufferAtomicOr, 1, 32},
|
||||
{0x3bu, Opcode::BufferAtomicXor, 1, 32},
|
||||
};
|
||||
|
||||
constexpr MemoryOpcodeInfo MTBUF_OPS[] = {
|
||||
{0x00u, Opcode::TBufferLoadFormatX, 1, 32, false, true, true},
|
||||
{0x01u, Opcode::TBufferLoadFormatXy, 2, 32, false, true, true},
|
||||
{0x02u, Opcode::TBufferLoadFormatXyz, 3, 32, false, true, true},
|
||||
{0x03u, Opcode::TBufferLoadFormatXyzw, 4, 32, false, true, true},
|
||||
{0x04u, Opcode::TBufferStoreFormatX, 1, 32, false, true, true},
|
||||
{0x05u, Opcode::TBufferStoreFormatXy, 2, 32, false, true, true},
|
||||
{0x06u, Opcode::TBufferStoreFormatXyz, 3, 32, false, true, true},
|
||||
{0x07u, Opcode::TBufferStoreFormatXyzw, 4, 32, false, true, true},
|
||||
};
|
||||
|
||||
constexpr MemoryOpcodeInfo FLAT_OPS[] = {
|
||||
{0x08u, Opcode::FlatLoadUbyte, 1, 8}, {0x09u, Opcode::FlatLoadSbyte, 1, 8, true},
|
||||
{0x0au, Opcode::FlatLoadUshort, 1, 16}, {0x0bu, Opcode::FlatLoadSshort, 1, 16, true},
|
||||
{0x0cu, Opcode::FlatLoadDword, 1, 32}, {0x0du, Opcode::FlatLoadDwordx2, 2, 32},
|
||||
{0x0eu, Opcode::FlatLoadDwordx4, 4, 32}, {0x0fu, Opcode::FlatLoadDwordx3, 3, 32},
|
||||
{0x18u, Opcode::FlatStoreByte, 1, 8}, {0x1au, Opcode::FlatStoreShort, 1, 16},
|
||||
{0x1cu, Opcode::FlatStoreDword, 1, 32}, {0x1du, Opcode::FlatStoreDwordx2, 2, 32},
|
||||
{0x1eu, Opcode::FlatStoreDwordx4, 4, 32}, {0x1fu, Opcode::FlatStoreDwordx3, 3, 32},
|
||||
};
|
||||
|
||||
constexpr MemoryOpcodeInfo DS_OPS[] = {
|
||||
{0x00u, Opcode::DsAddU32, 1, 32}, {0x01u, Opcode::DsSubU32, 1, 32},
|
||||
{0x05u, Opcode::DsMinI32, 1, 32}, {0x06u, Opcode::DsMaxI32, 1, 32},
|
||||
{0x07u, Opcode::DsMinU32, 1, 32}, {0x08u, Opcode::DsMaxU32, 1, 32},
|
||||
{0x09u, Opcode::DsAndB32, 1, 32}, {0x0au, Opcode::DsOrB32, 1, 32},
|
||||
{0x0bu, Opcode::DsXorB32, 1, 32}, {0x0du, Opcode::DsWriteB32, 1, 32},
|
||||
{0x0eu, Opcode::DsWrite2B32, 2, 32}, {0x0fu, Opcode::DsWrite2St64B32, 2, 32},
|
||||
{0x12u, Opcode::DsMinF32, 1, 32}, {0x13u, Opcode::DsMaxF32, 1, 32},
|
||||
{0x1eu, Opcode::DsWriteByte, 1, 8}, {0x1fu, Opcode::DsWriteShort, 1, 16},
|
||||
{0x20u, Opcode::DsAddRtnU32, 1, 32}, {0x21u, Opcode::DsSubRtnU32, 1, 32},
|
||||
{0x25u, Opcode::DsMinRtnI32, 1, 32}, {0x26u, Opcode::DsMaxRtnI32, 1, 32},
|
||||
{0x27u, Opcode::DsMinRtnU32, 1, 32}, {0x28u, Opcode::DsMaxRtnU32, 1, 32},
|
||||
{0x29u, Opcode::DsAndRtnB32, 1, 32}, {0x2au, Opcode::DsOrRtnB32, 1, 32},
|
||||
{0x2bu, Opcode::DsXorRtnB32, 1, 32}, {0x2du, Opcode::DsWrxchgRtnB32, 1, 32},
|
||||
{0x35u, Opcode::DsSwizzleB32, 1, 32}, {0x36u, Opcode::DsReadB32, 1, 32},
|
||||
{0x37u, Opcode::DsRead2B32, 2, 32}, {0x38u, Opcode::DsRead2B32, 2, 32},
|
||||
{0x39u, Opcode::DsReadSbyte, 1, 8, true}, {0x3au, Opcode::DsReadUbyte, 1, 8},
|
||||
{0x3bu, Opcode::DsReadSshort, 1, 16, true}, {0x3cu, Opcode::DsReadUshort, 1, 16},
|
||||
{0x3du, Opcode::DsConsume, 1, 32}, {0x3eu, Opcode::DsAppend, 1, 32},
|
||||
{0x4du, Opcode::DsWriteB64, 2, 32}, {0x4eu, Opcode::DsWrite2B64, 4, 32},
|
||||
{0x4fu, Opcode::DsWrite2St64B64, 4, 32}, {0x76u, Opcode::DsReadB64, 2, 32},
|
||||
{0x77u, Opcode::DsRead2B64, 4, 32}, {0x78u, Opcode::DsRead2St64B64, 4, 32},
|
||||
{0xb0u, Opcode::DsWriteAddtidB32, 1, 32}, {0xb1u, Opcode::DsReadAddtidB32, 1, 32},
|
||||
{0xdeu, Opcode::DsWriteB96, 3, 32}, {0xdfu, Opcode::DsWriteB128, 4, 32},
|
||||
{0xfeu, Opcode::DsReadB96, 3, 32}, {0xffu, Opcode::DsReadB128, 4, 32},
|
||||
};
|
||||
|
||||
const MemoryOpcodeInfo* LookupMemoryOpcode(const MemoryOpcodeInfo* ops, uint32_t count,
|
||||
uint32_t opcode) {
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
if (ops[i].opcode == opcode) {
|
||||
return &ops[i];
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32_t SignExtendU32(uint32_t value, uint32_t bits) {
|
||||
if (bits == 0u || bits >= 32u) {
|
||||
return value;
|
||||
}
|
||||
const uint32_t sign = 1u << (bits - 1u);
|
||||
return (value ^ sign) - sign;
|
||||
}
|
||||
|
||||
void MarkMemoryUnsupported(Instruction& inst, Family family, uint32_t opcode, const char* reason) {
|
||||
inst.family = family;
|
||||
inst.opcode_id = opcode;
|
||||
inst.opcode = Opcode::Unsupported;
|
||||
SetUnsupported(inst, family, opcode, reason);
|
||||
}
|
||||
|
||||
void ApplyMemoryInfo(Instruction& inst, const MemoryOpcodeInfo* info) {
|
||||
if (info == nullptr) {
|
||||
inst.opcode = Opcode::Unsupported;
|
||||
return;
|
||||
}
|
||||
inst.opcode = info->decoded;
|
||||
inst.data_dwords = info->data_dwords;
|
||||
inst.data_bits = info->data_bits;
|
||||
inst.data_signed = info->data_signed;
|
||||
inst.typed = info->typed;
|
||||
inst.formatted = info->formatted;
|
||||
}
|
||||
|
||||
bool IsDsWriteOpcode(Opcode opcode) {
|
||||
switch (opcode) {
|
||||
case Opcode::DsWriteByte:
|
||||
case Opcode::DsWriteShort:
|
||||
case Opcode::DsWrite2B32:
|
||||
case Opcode::DsWrite2St64B32:
|
||||
case Opcode::DsWrite2B64:
|
||||
case Opcode::DsWrite2St64B64:
|
||||
case Opcode::DsWriteB32:
|
||||
case Opcode::DsWriteB64:
|
||||
case Opcode::DsWriteB96:
|
||||
case Opcode::DsWriteB128: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsDsAtomicOpcode(Opcode opcode) {
|
||||
switch (opcode) {
|
||||
case Opcode::DsAddU32:
|
||||
case Opcode::DsAddRtnU32:
|
||||
case Opcode::DsSubU32:
|
||||
case Opcode::DsSubRtnU32:
|
||||
case Opcode::DsMinI32:
|
||||
case Opcode::DsMinRtnI32:
|
||||
case Opcode::DsMaxI32:
|
||||
case Opcode::DsMaxRtnI32:
|
||||
case Opcode::DsMinU32:
|
||||
case Opcode::DsMinRtnU32:
|
||||
case Opcode::DsMaxU32:
|
||||
case Opcode::DsMaxRtnU32:
|
||||
case Opcode::DsAndB32:
|
||||
case Opcode::DsAndRtnB32:
|
||||
case Opcode::DsOrB32:
|
||||
case Opcode::DsOrRtnB32:
|
||||
case Opcode::DsXorB32:
|
||||
case Opcode::DsXorRtnB32:
|
||||
case Opcode::DsWrxchgRtnB32: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t DsSourceCount(Opcode opcode) {
|
||||
switch (opcode) {
|
||||
case Opcode::DsWrite2B32:
|
||||
case Opcode::DsWrite2St64B32:
|
||||
case Opcode::DsWrite2B64:
|
||||
case Opcode::DsWrite2St64B64:
|
||||
case Opcode::DsMinF32:
|
||||
case Opcode::DsMaxF32: return 3u;
|
||||
case Opcode::DsReadAddtidB32:
|
||||
case Opcode::DsConsume:
|
||||
case Opcode::DsAppend: return 0u;
|
||||
default: return IsDsWriteOpcode(opcode) || IsDsAtomicOpcode(opcode) ? 2u : 1u;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsFlatStoreOpcode(Opcode opcode) {
|
||||
switch (opcode) {
|
||||
case Opcode::FlatStoreByte:
|
||||
case Opcode::FlatStoreShort:
|
||||
case Opcode::FlatStoreDword:
|
||||
case Opcode::FlatStoreDwordx2:
|
||||
case Opcode::FlatStoreDwordx3:
|
||||
case Opcode::FlatStoreDwordx4: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool DecodeSmem(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error) {
|
||||
if (word_index + 1u >= code.size()) {
|
||||
if (error != nullptr) {
|
||||
*error = fmt::format("truncated SMEM instruction at pc 0x{:08x}", pc);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32_t word0 = code[word_index];
|
||||
const uint32_t word1 = code[word_index + 1u];
|
||||
const uint32_t opcode = (word0 >> 18u) & 0xffu;
|
||||
const uint32_t sdst = (word0 >> 6u) & 0x7fu;
|
||||
const uint32_t sbase = word0 & 0x3fu;
|
||||
const uint32_t soffset = (word1 >> 25u) & 0x7fu;
|
||||
|
||||
inst.pc = pc;
|
||||
inst.word = word0;
|
||||
inst.word_count = 2;
|
||||
inst.offset = SignExtendU32(word1 & 0x1fffffu, 21u);
|
||||
inst.glc = ((word0 >> 16u) & 1u) != 0;
|
||||
inst.family = Family::SMEM;
|
||||
inst.opcode_id = opcode;
|
||||
const auto* info =
|
||||
LookupMemoryOpcode(SMEM_OPS, static_cast<uint32_t>(std::size(SMEM_OPS)), opcode);
|
||||
ApplyMemoryInfo(inst, info);
|
||||
SetRawWords(inst, code, word_index, 2);
|
||||
if (inst.opcode == Opcode::Unsupported) {
|
||||
MarkMemoryUnsupported(inst, Family::SMEM, opcode, "SMEM opcode is not implemented");
|
||||
}
|
||||
|
||||
DecodeScalarDestination(sdst, pc, inst.dst, nullptr);
|
||||
// SMEM encodes SBASE in SGPR pairs. Scalar-buffer loads still use the same
|
||||
// pair index; their descriptor operand consumes four SGPRs from that base.
|
||||
DecodeScalarSource(sbase * 2u, pc, inst.src0, nullptr);
|
||||
DecodeScalarSource(soffset, pc, inst.src1, nullptr);
|
||||
inst.src_count = 2;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DecodeMubuf(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
Instruction& inst, std::string* error) {
|
||||
if (word_index + 1u >= code.size()) {
|
||||
if (error != nullptr) {
|
||||
*error = fmt::format("truncated MUBUF instruction at pc 0x{:08x}", pc);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32_t word0 = code[word_index];
|
||||
const uint32_t word1 = code[word_index + 1u];
|
||||
const uint32_t opcode = ((word0 >> 18u) & 0x7fu) | (((word0 >> 25u) & 1u) << 7u);
|
||||
const uint32_t vdata = (word1 >> 8u) & 0xffu;
|
||||
const uint32_t vaddr = word1 & 0xffu;
|
||||
const uint32_t srsrc = (word1 >> 16u) & 0x1fu;
|
||||
const uint32_t soffset = (word1 >> 24u) & 0xffu;
|
||||
|
||||
inst.pc = pc;
|
||||
inst.word = word0;
|
||||
inst.word_count = 2;
|
||||
inst.offset = word0 & 0xfffu;
|
||||
inst.idxen = ((word0 >> 13u) & 1u) != 0;
|
||||
inst.offen = ((word0 >> 12u) & 1u) != 0;
|
||||
inst.glc = ((word0 >> 14u) & 1u) != 0;
|
||||
inst.slc = ((word1 >> 22u) & 1u) != 0;
|
||||
inst.family = Family::MUBUF;
|
||||
inst.opcode_id = opcode;
|
||||
const auto* info =
|
||||
LookupMemoryOpcode(MUBUF_OPS, static_cast<uint32_t>(std::size(MUBUF_OPS)), opcode);
|
||||
ApplyMemoryInfo(inst, info);
|
||||
SetRawWords(inst, code, word_index, 2);
|
||||
if (inst.opcode == Opcode::Unsupported) {
|
||||
MarkMemoryUnsupported(inst, Family::MUBUF, opcode, "MUBUF opcode is not implemented");
|
||||
}
|
||||
|
||||
DecodeVectorGpr(vdata, inst.dst, nullptr);
|
||||
DecodeVectorGpr(vaddr, inst.src0, nullptr);
|
||||
DecodeScalarSource(srsrc * 4u, pc, inst.src1, nullptr);
|
||||
DecodeScalarSource(soffset, pc, inst.src2, nullptr);
|
||||
inst.src_count = 3;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DecodeMtbuf(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
Instruction& inst, std::string* error) {
|
||||
if (word_index + 1u >= code.size()) {
|
||||
if (error != nullptr) {
|
||||
*error = fmt::format("truncated MTBUF instruction at pc 0x{:08x}", pc);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32_t word0 = code[word_index];
|
||||
const uint32_t word1 = code[word_index + 1u];
|
||||
const uint32_t opcode = ((word0 >> 16u) & 0x7u) | (((word1 >> 21u) & 1u) << 3u);
|
||||
const uint32_t dfmt = (word0 >> 19u) & 0xfu;
|
||||
const uint32_t nfmt = (word0 >> 23u) & 0x7u;
|
||||
const uint32_t vdata = (word1 >> 8u) & 0xffu;
|
||||
const uint32_t vaddr = word1 & 0xffu;
|
||||
const uint32_t srsrc = (word1 >> 16u) & 0x1fu;
|
||||
const uint32_t soffset = (word1 >> 24u) & 0xffu;
|
||||
|
||||
inst.pc = pc;
|
||||
inst.word = word0;
|
||||
inst.word_count = 2;
|
||||
inst.offset = word0 & 0xfffu;
|
||||
inst.idxen = ((word0 >> 13u) & 1u) != 0;
|
||||
inst.offen = ((word0 >> 12u) & 1u) != 0;
|
||||
inst.glc = ((word0 >> 14u) & 1u) != 0;
|
||||
inst.slc = ((word1 >> 22u) & 1u) != 0;
|
||||
inst.family = Family::MTBUF;
|
||||
inst.opcode_id = opcode;
|
||||
inst.data_format = dfmt;
|
||||
inst.number_format = nfmt;
|
||||
const auto* info =
|
||||
LookupMemoryOpcode(MTBUF_OPS, static_cast<uint32_t>(std::size(MTBUF_OPS)), opcode);
|
||||
ApplyMemoryInfo(inst, info);
|
||||
SetRawWords(inst, code, word_index, 2);
|
||||
if (inst.opcode == Opcode::Unsupported) {
|
||||
MarkMemoryUnsupported(inst, Family::MTBUF, opcode, "MTBUF opcode is not implemented");
|
||||
}
|
||||
|
||||
DecodeVectorGpr(vdata, inst.dst, nullptr);
|
||||
DecodeVectorGpr(vaddr, inst.src0, nullptr);
|
||||
DecodeScalarSource(srsrc * 4u, pc, inst.src1, nullptr);
|
||||
DecodeScalarSource(soffset, pc, inst.src2, nullptr);
|
||||
inst.src_count = 3;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DecodeFlat(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error) {
|
||||
if (word_index + 1u >= code.size()) {
|
||||
if (error != nullptr) {
|
||||
*error = fmt::format("truncated FLAT instruction at pc 0x{:08x}", pc);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32_t word0 = code[word_index];
|
||||
const uint32_t word1 = code[word_index + 1u];
|
||||
const uint32_t offset = word0 & 0xfffu;
|
||||
const uint32_t dlc = (word0 >> 12u) & 1u;
|
||||
const uint32_t lds = (word0 >> 13u) & 1u;
|
||||
const uint32_t seg = (word0 >> 14u) & 0x3u;
|
||||
const uint32_t opcode = (word0 >> 18u) & 0x7fu;
|
||||
const uint32_t vdst = (word1 >> 24u) & 0xffu;
|
||||
const uint32_t saddr = (word1 >> 16u) & 0x7fu;
|
||||
const uint32_t data = (word1 >> 8u) & 0xffu;
|
||||
const uint32_t addr = word1 & 0xffu;
|
||||
|
||||
inst.pc = pc;
|
||||
inst.word = word0;
|
||||
inst.word_count = 2;
|
||||
inst.offset = seg == 0u ? (offset & 0x7ffu) : SignExtendU32(offset, 12u);
|
||||
inst.glc = ((word0 >> 16u) & 1u) != 0;
|
||||
inst.slc = ((word0 >> 17u) & 1u) != 0;
|
||||
inst.family = Family::FLAT;
|
||||
inst.opcode_id = opcode;
|
||||
inst.memory_segment = seg;
|
||||
const auto* info =
|
||||
LookupMemoryOpcode(FLAT_OPS, static_cast<uint32_t>(std::size(FLAT_OPS)), opcode);
|
||||
ApplyMemoryInfo(inst, info);
|
||||
SetRawWords(inst, code, word_index, 2);
|
||||
|
||||
if (dlc != 0 || lds != 0 || inst.glc || inst.slc || seg == 3u) {
|
||||
SetUnsupported(inst, Family::FLAT, opcode, "FLAT modifiers or segment are not implemented");
|
||||
return true;
|
||||
}
|
||||
if (inst.opcode == Opcode::Unsupported) {
|
||||
MarkMemoryUnsupported(inst, Family::FLAT, opcode, "FLAT opcode is not implemented");
|
||||
return true;
|
||||
}
|
||||
|
||||
DecodeVectorGpr(IsFlatStoreOpcode(inst.opcode) ? data : vdst, inst.dst, nullptr);
|
||||
DecodeVectorGpr(addr, inst.src0, nullptr);
|
||||
inst.src_count = 1;
|
||||
if (seg == 0u || saddr == 0x7du || saddr == 0x7fu) {
|
||||
DecodeVectorGpr(addr + 1u, inst.src1, nullptr);
|
||||
inst.src_count = 2;
|
||||
} else {
|
||||
DecodeScalarSource(saddr, pc, inst.src1, nullptr);
|
||||
inst.src_count = 2;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DecodeDs(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error) {
|
||||
if (word_index + 1u >= code.size()) {
|
||||
if (error != nullptr) {
|
||||
*error = fmt::format("truncated DS instruction at pc 0x{:08x}", pc);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32_t word0 = code[word_index];
|
||||
const uint32_t word1 = code[word_index + 1u];
|
||||
const uint32_t opcode = (word0 >> 18u) & 0xffu;
|
||||
const uint32_t offset0 = word0 & 0xffu;
|
||||
const uint32_t offset1 = (word0 >> 8u) & 0xffu;
|
||||
const uint32_t vdst = (word1 >> 24u) & 0xffu;
|
||||
const uint32_t data1 = (word1 >> 16u) & 0xffu;
|
||||
const uint32_t data0 = (word1 >> 8u) & 0xffu;
|
||||
const uint32_t addr = word1 & 0xffu;
|
||||
|
||||
inst.pc = pc;
|
||||
inst.word = word0;
|
||||
inst.word_count = 2;
|
||||
inst.offset = offset0 | (offset1 << 8u);
|
||||
inst.gds = ((word0 >> 17u) & 1u) != 0u;
|
||||
inst.family = Family::DS;
|
||||
inst.opcode_id = opcode;
|
||||
const auto* info = LookupMemoryOpcode(DS_OPS, static_cast<uint32_t>(std::size(DS_OPS)), opcode);
|
||||
ApplyMemoryInfo(inst, info);
|
||||
SetRawWords(inst, code, word_index, 2);
|
||||
if (inst.opcode == Opcode::Unsupported) {
|
||||
MarkMemoryUnsupported(inst, Family::DS, opcode, "DS opcode is not implemented");
|
||||
}
|
||||
if (inst.opcode == Opcode::DsSwizzleB32 && inst.offset >= 0xe000u) {
|
||||
SetUnsupported(inst, Family::DS, opcode, "DS swizzle FFT mode is not implemented");
|
||||
}
|
||||
if (inst.gds &&
|
||||
(inst.opcode == Opcode::DsSwizzleB32 || inst.opcode == Opcode::DsWriteAddtidB32 ||
|
||||
inst.opcode == Opcode::DsReadAddtidB32)) {
|
||||
SetUnsupported(inst, Family::DS, opcode, "DS swizzle/addtid is available only for LDS");
|
||||
}
|
||||
if (inst.gds && (inst.opcode == Opcode::DsAppend || inst.opcode == Opcode::DsConsume) &&
|
||||
inst.offset != 0u) {
|
||||
SetUnsupported(inst, Family::DS, opcode,
|
||||
"GDS append/consume requires a zero instruction offset");
|
||||
}
|
||||
if (inst.opcode == Opcode::DsWriteAddtidB32 && data1 != 0u) {
|
||||
SetUnsupported(inst, Family::DS, opcode,
|
||||
"DS write addtid data1 operand is not implemented");
|
||||
}
|
||||
if (inst.opcode == Opcode::DsReadAddtidB32 && (data0 != 0u || data1 != 0u)) {
|
||||
SetUnsupported(inst, Family::DS, opcode,
|
||||
"DS read addtid data operands are not implemented");
|
||||
}
|
||||
if (inst.opcode == Opcode::DsWrite2B32 || opcode == 0x37u) {
|
||||
inst.offset = offset0 * 4u;
|
||||
inst.secondary_offset = offset1 * 4u;
|
||||
} else if (inst.opcode == Opcode::DsWrite2St64B32 || opcode == 0x38u) {
|
||||
inst.offset = offset0 * 256u;
|
||||
inst.secondary_offset = offset1 * 256u;
|
||||
} else if (inst.opcode == Opcode::DsWrite2B64 || inst.opcode == Opcode::DsRead2B64) {
|
||||
inst.offset = offset0 * 8u;
|
||||
inst.secondary_offset = offset1 * 8u;
|
||||
} else if (inst.opcode == Opcode::DsWrite2St64B64 || inst.opcode == Opcode::DsRead2St64B64) {
|
||||
inst.offset = offset0 * 512u;
|
||||
inst.secondary_offset = offset1 * 512u;
|
||||
}
|
||||
|
||||
DecodeVectorGpr(vdst, inst.dst, nullptr);
|
||||
DecodeVectorGpr(addr, inst.src0, nullptr);
|
||||
DecodeVectorGpr(data0, inst.src1, nullptr);
|
||||
DecodeVectorGpr(data1, inst.src2, nullptr);
|
||||
inst.src_count = DsSourceCount(inst.opcode);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Decoder
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_RECOMPILER_MEMORYOPS_H_
|
||||
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_RECOMPILER_MEMORYOPS_H_
|
||||
|
||||
#include "graphics/shader/recompiler/decompiler/ShaderDecoder.h"
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Decoder {
|
||||
|
||||
bool DecodeSmem(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error);
|
||||
bool DecodeMubuf(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
Instruction& inst, std::string* error);
|
||||
bool DecodeMtbuf(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
Instruction& inst, std::string* error);
|
||||
bool DecodeFlat(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error);
|
||||
bool DecodeDs(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error);
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Decoder
|
||||
|
||||
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_RECOMPILER_MEMORYOPS_H_ */
|
||||
@@ -0,0 +1,283 @@
|
||||
#include "graphics/shader/recompiler/decompiler/ScalarAluOps.h"
|
||||
|
||||
#include <iterator>
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Decoder {
|
||||
namespace {
|
||||
|
||||
struct OpcodeMap {
|
||||
uint32_t opcode = 0;
|
||||
Opcode ir = Opcode::Unknown;
|
||||
};
|
||||
|
||||
constexpr OpcodeMap SOP2_OPS[] = {
|
||||
{0x00u, Opcode::SAddU32}, {0x01u, Opcode::SSubU32}, {0x02u, Opcode::SAddI32},
|
||||
{0x03u, Opcode::SSubI32}, {0x04u, Opcode::SAddcU32}, {0x05u, Opcode::SSubbU32},
|
||||
{0x06u, Opcode::SMinI32}, {0x07u, Opcode::SMinU32}, {0x08u, Opcode::SMaxI32},
|
||||
{0x09u, Opcode::SMaxU32}, {0x0au, Opcode::SCselectB32}, {0x0bu, Opcode::SCselectB64},
|
||||
{0x0eu, Opcode::SAndB32}, {0x0fu, Opcode::SAndB64}, {0x10u, Opcode::SOrB32},
|
||||
{0x11u, Opcode::SOrB64}, {0x12u, Opcode::SXorB32}, {0x13u, Opcode::SXorB64},
|
||||
{0x14u, Opcode::SAndn2B32}, {0x15u, Opcode::SAndn2B64}, {0x16u, Opcode::SOrn2B32},
|
||||
{0x17u, Opcode::SOrn2B64}, {0x18u, Opcode::SNandB32}, {0x19u, Opcode::SNandB64},
|
||||
{0x1au, Opcode::SNorB32}, {0x1bu, Opcode::SNorB64}, {0x1cu, Opcode::SXnorB32},
|
||||
{0x1du, Opcode::SXnorB64}, {0x1eu, Opcode::SLshlB32}, {0x1fu, Opcode::SLshlB64},
|
||||
{0x20u, Opcode::SLshrB32}, {0x21u, Opcode::SLshrB64}, {0x22u, Opcode::SAshrI32},
|
||||
{0x24u, Opcode::SBfmB32}, {0x25u, Opcode::SBfmB64}, {0x26u, Opcode::SMulI32},
|
||||
{0x27u, Opcode::SBfeU32}, {0x29u, Opcode::SBfeU64}, {0x2eu, Opcode::SLshl1AddU32},
|
||||
{0x2fu, Opcode::SLshl2AddU32}, {0x30u, Opcode::SLshl3AddU32}, {0x31u, Opcode::SLshl4AddU32},
|
||||
{0x32u, Opcode::SPackLlB32B16}, {0x33u, Opcode::SPackLhB32B16}, {0x34u, Opcode::SPackHhB32B16},
|
||||
{0x35u, Opcode::SMulHiU32},
|
||||
};
|
||||
|
||||
constexpr OpcodeMap SOP1_OPS[] = {
|
||||
{0x03u, Opcode::SMovB32},
|
||||
{0x04u, Opcode::SMovB64},
|
||||
{0x07u, Opcode::SNotB32},
|
||||
{0x08u, Opcode::SNotB64},
|
||||
{0x0au, Opcode::SWqmB64},
|
||||
{0x0bu, Opcode::SBrevB32},
|
||||
{0x0fu, Opcode::SBcnt1I32B32},
|
||||
{0x10u, Opcode::SBcnt1I32B64},
|
||||
{0x13u, Opcode::SFf1I32B32},
|
||||
{0x16u, Opcode::SFlbitI32B64},
|
||||
{0x1bu, Opcode::SBitset0B32},
|
||||
{0x1du, Opcode::SBitset1B32},
|
||||
{0x1fu, Opcode::SGetpcB64},
|
||||
{0x20u, Opcode::SSetpcB64},
|
||||
{0x24u, Opcode::SAndSaveexecB64},
|
||||
{0x28u, Opcode::SOrn2SaveexecB64},
|
||||
{0x34u, Opcode::SAbsI32},
|
||||
{0x37u, Opcode::SAndn1SaveexecB64},
|
||||
{0x3bu, Opcode::SBitreplicateB64B32},
|
||||
{0x3cu, Opcode::SAndSaveexecB32},
|
||||
{0x44u, Opcode::SAndn1SaveexecB32},
|
||||
};
|
||||
|
||||
constexpr OpcodeMap SOPC_OPS[] = {
|
||||
{0x00u, Opcode::SCmpEqI32}, {0x01u, Opcode::SCmpLgI32}, {0x02u, Opcode::SCmpGtI32},
|
||||
{0x03u, Opcode::SCmpGeI32}, {0x04u, Opcode::SCmpLtI32}, {0x05u, Opcode::SCmpLeI32},
|
||||
{0x06u, Opcode::SCmpEqU32}, {0x07u, Opcode::SCmpLgU32}, {0x08u, Opcode::SCmpGtU32},
|
||||
{0x09u, Opcode::SCmpGeU32}, {0x0au, Opcode::SCmpLtU32}, {0x0bu, Opcode::SCmpLeU32},
|
||||
{0x0cu, Opcode::SBitcmp0B32}, {0x0du, Opcode::SBitcmp1B32}, {0x13u, Opcode::SCmpLgU64},
|
||||
};
|
||||
|
||||
constexpr OpcodeMap SOPK_OPS[] = {
|
||||
{0x00u, Opcode::SMovkI32}, {0x03u, Opcode::SCmpEqI32}, {0x04u, Opcode::SCmpLgI32},
|
||||
{0x05u, Opcode::SCmpGtI32}, {0x06u, Opcode::SCmpGeI32}, {0x07u, Opcode::SCmpLtI32},
|
||||
{0x08u, Opcode::SCmpLeI32}, {0x09u, Opcode::SCmpEqU32}, {0x0au, Opcode::SCmpLgU32},
|
||||
{0x0bu, Opcode::SCmpGtU32}, {0x0cu, Opcode::SCmpGeU32}, {0x0du, Opcode::SCmpLtU32},
|
||||
{0x0eu, Opcode::SCmpLeU32}, {0x0fu, Opcode::SAddI32}, {0x10u, Opcode::SMulkI32},
|
||||
{0x13u, Opcode::SSetregB32}, {0x17u, Opcode::SWaitcnt}, {0x18u, Opcode::SWaitcnt},
|
||||
{0x19u, Opcode::SWaitcnt}, {0x1au, Opcode::SWaitcnt},
|
||||
};
|
||||
|
||||
constexpr OpcodeMap SOPP_OPS[] = {
|
||||
{0x00u, Opcode::SNop}, {0x01u, Opcode::SEndpgm}, {0x02u, Opcode::SBranch},
|
||||
{0x04u, Opcode::SCbranchScc0}, {0x05u, Opcode::SCbranchScc1}, {0x06u, Opcode::SCbranchVccz},
|
||||
{0x07u, Opcode::SCbranchVccnz}, {0x08u, Opcode::SCbranchExecz}, {0x09u, Opcode::SCbranchExecnz},
|
||||
{0x0au, Opcode::SBarrier}, {0x0cu, Opcode::SWaitcnt}, {0x0eu, Opcode::SSleep},
|
||||
{0x10u, Opcode::SSendmsg}, {0x16u, Opcode::STtraceData}, {0x20u, Opcode::SInstPrefetch},
|
||||
};
|
||||
|
||||
Opcode Lookup(const OpcodeMap* ops, uint32_t count, uint32_t opcode) {
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
if (ops[i].opcode == opcode) {
|
||||
return ops[i].ir;
|
||||
}
|
||||
}
|
||||
return Opcode::Unsupported;
|
||||
}
|
||||
|
||||
bool DecodeBinarySources(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
Instruction& inst, uint32_t ssrc0, uint32_t ssrc1, std::string* error) {
|
||||
if (!DecodeScalarSource(ssrc0, pc, inst.src0, error) ||
|
||||
!DecodeScalarSource(ssrc1, pc, inst.src1, error)) {
|
||||
return false;
|
||||
}
|
||||
inst.src_count = 2;
|
||||
return ReadLiteralOperands(code, word_index, inst, error);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool DecodeSop1(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error) {
|
||||
const uint32_t word = code[word_index];
|
||||
const uint32_t opcode = (word >> 8u) & 0xffu;
|
||||
const uint32_t ssrc0 = word & 0xffu;
|
||||
const uint32_t sdst = (word >> 16u) & 0x7fu;
|
||||
|
||||
inst.pc = pc;
|
||||
inst.word = word;
|
||||
inst.family = Family::SOP1;
|
||||
inst.opcode_id = opcode;
|
||||
inst.opcode = Lookup(SOP1_OPS, static_cast<uint32_t>(std::size(SOP1_OPS)), opcode);
|
||||
SetRawWords(inst, code, word_index, 1);
|
||||
|
||||
if (inst.opcode == Opcode::Unsupported) {
|
||||
SetUnsupported(inst, Family::SOP1, opcode, "SOP1 opcode is not implemented");
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (inst.opcode) {
|
||||
case Opcode::SGetpcB64:
|
||||
inst.src_count = 0;
|
||||
return DecodeScalarDestination(sdst, pc, inst.dst, error);
|
||||
case Opcode::SSetpcB64:
|
||||
inst.src_count = 1;
|
||||
inst.dst.kind = OperandKind::Null;
|
||||
if (!DecodeScalarSource(ssrc0, pc, inst.src0, error)) {
|
||||
return false;
|
||||
}
|
||||
return ReadLiteralOperands(code, word_index, inst, error);
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (!DecodeScalarSource(ssrc0, pc, inst.src0, error) ||
|
||||
!DecodeScalarDestination(sdst, pc, inst.dst, error)) {
|
||||
return false;
|
||||
}
|
||||
inst.src_count = 1;
|
||||
return ReadLiteralOperands(code, word_index, inst, error);
|
||||
}
|
||||
|
||||
bool DecodeSop2(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error) {
|
||||
const uint32_t word = code[word_index];
|
||||
const uint32_t opcode = (word >> 23u) & 0x7fu;
|
||||
const uint32_t ssrc1 = (word >> 8u) & 0xffu;
|
||||
const uint32_t ssrc0 = word & 0xffu;
|
||||
const uint32_t sdst = (word >> 16u) & 0x7fu;
|
||||
|
||||
inst.pc = pc;
|
||||
inst.word = word;
|
||||
inst.family = Family::SOP2;
|
||||
inst.opcode_id = opcode;
|
||||
inst.opcode = Lookup(SOP2_OPS, static_cast<uint32_t>(std::size(SOP2_OPS)), opcode);
|
||||
SetRawWords(inst, code, word_index, 1);
|
||||
|
||||
if (inst.opcode == Opcode::Unsupported) {
|
||||
SetUnsupported(inst, Family::SOP2, opcode, "SOP2 opcode is not implemented");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!DecodeScalarDestination(sdst, pc, inst.dst, error)) {
|
||||
return false;
|
||||
}
|
||||
return DecodeBinarySources(pc, code, word_index, inst, ssrc0, ssrc1, error);
|
||||
}
|
||||
|
||||
bool DecodeSopk(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error) {
|
||||
const uint32_t word = code[word_index];
|
||||
const uint32_t opcode = (word >> 23u) & 0x1fu;
|
||||
const uint32_t sdst = (word >> 16u) & 0x7fu;
|
||||
const auto imm = static_cast<int16_t>(word & 0xffffu);
|
||||
|
||||
(void)error;
|
||||
|
||||
inst.pc = pc;
|
||||
inst.word = word;
|
||||
inst.family = Family::SOPK;
|
||||
inst.opcode_id = opcode;
|
||||
inst.opcode = Lookup(SOPK_OPS, static_cast<uint32_t>(std::size(SOPK_OPS)), opcode);
|
||||
inst.src0.kind = OperandKind::IntegerInlineConstant;
|
||||
inst.src0.signed_val = imm;
|
||||
inst.src0.value = static_cast<uint32_t>(imm);
|
||||
inst.src_count = 1;
|
||||
SetRawWords(inst, code, word_index, 1);
|
||||
|
||||
if (inst.opcode == Opcode::Unsupported) {
|
||||
SetUnsupported(inst, Family::SOPK, opcode, "SOPK opcode is not implemented");
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (inst.opcode) {
|
||||
case Opcode::SMovkI32: return DecodeScalarDestination(sdst, pc, inst.dst, error);
|
||||
case Opcode::SWaitcnt: {
|
||||
const uint32_t waitcnt = word & 0xffffu;
|
||||
inst.dst.kind = OperandKind::Null;
|
||||
inst.src0.signed_val = static_cast<int32_t>(waitcnt);
|
||||
inst.src0.value = waitcnt;
|
||||
inst.src_count = 1;
|
||||
return true;
|
||||
}
|
||||
case Opcode::SSetregB32:
|
||||
inst.dst.kind = OperandKind::Null;
|
||||
inst.src1.kind = OperandKind::LiteralConstant;
|
||||
inst.src1.value = word & 0xffffu;
|
||||
inst.src1.signed_val = static_cast<int32_t>(imm);
|
||||
inst.src_count = 2;
|
||||
return DecodeScalarSource(sdst, pc, inst.src0, error);
|
||||
default: break;
|
||||
}
|
||||
|
||||
inst.src1 = inst.src0;
|
||||
if (!DecodeScalarSource(sdst, pc, inst.src0, error)) {
|
||||
return false;
|
||||
}
|
||||
if (inst.opcode == Opcode::SAddI32 || inst.opcode == Opcode::SMulkI32) {
|
||||
inst.src_count = 2;
|
||||
return DecodeScalarDestination(sdst, pc, inst.dst, error);
|
||||
}
|
||||
|
||||
inst.dst.kind = OperandKind::Scc;
|
||||
inst.src_count = 2;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DecodeSopc(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error) {
|
||||
const uint32_t word = code[word_index];
|
||||
const uint32_t ssrc1 = (word >> 8u) & 0xffu;
|
||||
const uint32_t ssrc0 = word & 0xffu;
|
||||
const uint32_t opcode = (word >> 16u) & 0x7fu;
|
||||
|
||||
inst.pc = pc;
|
||||
inst.word = word;
|
||||
inst.family = Family::SOPC;
|
||||
inst.opcode_id = opcode;
|
||||
inst.opcode = Lookup(SOPC_OPS, static_cast<uint32_t>(std::size(SOPC_OPS)), opcode);
|
||||
inst.dst.kind = OperandKind::Scc;
|
||||
SetRawWords(inst, code, word_index, 1);
|
||||
|
||||
if (inst.opcode == Opcode::Unsupported) {
|
||||
SetUnsupported(inst, Family::SOPC, opcode, "SOPC opcode is not implemented");
|
||||
return true;
|
||||
}
|
||||
|
||||
return DecodeBinarySources(pc, code, word_index, inst, ssrc0, ssrc1, error);
|
||||
}
|
||||
|
||||
bool DecodeSopp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error) {
|
||||
const uint32_t word = code[word_index];
|
||||
const uint32_t opcode = (word >> 16u) & 0x7fu;
|
||||
const uint32_t simm = word & 0xffffu;
|
||||
|
||||
(void)error;
|
||||
|
||||
inst.pc = pc;
|
||||
inst.word = word;
|
||||
inst.family = Family::SOPP;
|
||||
inst.opcode_id = opcode;
|
||||
inst.opcode = Lookup(SOPP_OPS, static_cast<uint32_t>(std::size(SOPP_OPS)), opcode);
|
||||
inst.src0.kind = OperandKind::LiteralConstant;
|
||||
inst.src0.value = simm;
|
||||
inst.src0.signed_val = static_cast<int16_t>(simm);
|
||||
inst.src_count = (inst.opcode == Opcode::SNop || inst.opcode == Opcode::SWaitcnt ||
|
||||
inst.opcode == Opcode::SSleep || inst.opcode == Opcode::SSendmsg ||
|
||||
inst.opcode == Opcode::STtraceData || inst.opcode == Opcode::SInstPrefetch)
|
||||
? 1
|
||||
: 0;
|
||||
inst.branch_offset = static_cast<int32_t>(static_cast<int16_t>(simm)) * 4;
|
||||
inst.branch_target = pc + 4u + static_cast<uint32_t>(inst.branch_offset);
|
||||
SetRawWords(inst, code, word_index, 1);
|
||||
|
||||
if (inst.opcode == Opcode::Unsupported) {
|
||||
SetUnsupported(inst, Family::SOPP, opcode, "SOPP control-flow opcode is not implemented");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Decoder
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_RECOMPILER_SCALARALUOPS_H_
|
||||
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_RECOMPILER_SCALARALUOPS_H_
|
||||
|
||||
#include "graphics/shader/recompiler/decompiler/ShaderDecoder.h"
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Decoder {
|
||||
|
||||
bool DecodeSop1(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error);
|
||||
bool DecodeSop2(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error);
|
||||
bool DecodeSopk(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error);
|
||||
bool DecodeSopc(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error);
|
||||
bool DecodeSopp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error);
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Decoder
|
||||
|
||||
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_RECOMPILER_SCALARALUOPS_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,680 @@
|
||||
#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_RECOMPILER_SHADERDECODER_H_
|
||||
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_RECOMPILER_SHADERDECODER_H_
|
||||
|
||||
#include "common/common.h"
|
||||
#include "common/stringUtils.h"
|
||||
|
||||
#include <span>
|
||||
#include <vector>
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Decoder {
|
||||
|
||||
enum class Family {
|
||||
Unknown,
|
||||
SOP1,
|
||||
SOP2,
|
||||
SOPK,
|
||||
SOPC,
|
||||
SOPP,
|
||||
VOP1,
|
||||
VOP2,
|
||||
VOP3,
|
||||
VOP3P,
|
||||
VOPC,
|
||||
VINTRP,
|
||||
SMEM,
|
||||
MUBUF,
|
||||
MTBUF,
|
||||
FLAT,
|
||||
DS,
|
||||
MIMG,
|
||||
EXP
|
||||
};
|
||||
|
||||
enum class Opcode {
|
||||
Unknown,
|
||||
Unsupported,
|
||||
|
||||
SMovB32,
|
||||
SMovB64,
|
||||
SMovkI32,
|
||||
SAbsI32,
|
||||
SBrevB32,
|
||||
SBcnt1I32B32,
|
||||
SBcnt1I32B64,
|
||||
SFf1I32B32,
|
||||
SFlbitI32B64,
|
||||
SBitreplicateB64B32,
|
||||
SGetpcB64,
|
||||
SSetpcB64,
|
||||
SAndSaveexecB32,
|
||||
SAndn1SaveexecB32,
|
||||
SAndSaveexecB64,
|
||||
SOrn2SaveexecB64,
|
||||
SAndn1SaveexecB64,
|
||||
SNotB32,
|
||||
SNotB64,
|
||||
SWqmB64,
|
||||
SAddU32,
|
||||
SAddcU32,
|
||||
SSubbU32,
|
||||
SSubU32,
|
||||
SAddI32,
|
||||
SSubI32,
|
||||
SBitcmp0B32,
|
||||
SBitcmp1B32,
|
||||
SBitset0B32,
|
||||
SBitset1B32,
|
||||
SMinI32,
|
||||
SMaxI32,
|
||||
SMinU32,
|
||||
SMaxU32,
|
||||
SAndB32,
|
||||
SAndB64,
|
||||
SAndn2B32,
|
||||
SAndn2B64,
|
||||
SOrB32,
|
||||
SOrB64,
|
||||
SOrn2B32,
|
||||
SOrn2B64,
|
||||
SXorB32,
|
||||
SXorB64,
|
||||
SNandB32,
|
||||
SNandB64,
|
||||
SNorB32,
|
||||
SNorB64,
|
||||
SXnorB32,
|
||||
SXnorB64,
|
||||
SLshlB32,
|
||||
SLshlB64,
|
||||
SLshl1AddU32,
|
||||
SLshl2AddU32,
|
||||
SLshl3AddU32,
|
||||
SLshl4AddU32,
|
||||
SLshrB32,
|
||||
SLshrB64,
|
||||
SAshrI32,
|
||||
SMulI32,
|
||||
SMulHiU32,
|
||||
SMulkI32,
|
||||
SBfeU32,
|
||||
SBfeU64,
|
||||
SBfmB32,
|
||||
SBfmB64,
|
||||
SCselectB32,
|
||||
SCselectB64,
|
||||
SPackLlB32B16,
|
||||
SPackLhB32B16,
|
||||
SPackHhB32B16,
|
||||
SCmpEqI32,
|
||||
SCmpLgI32,
|
||||
SCmpGtI32,
|
||||
SCmpGeI32,
|
||||
SCmpLtI32,
|
||||
SCmpLeI32,
|
||||
SCmpEqU32,
|
||||
SCmpLgU32,
|
||||
SCmpGtU32,
|
||||
SCmpGeU32,
|
||||
SCmpLtU32,
|
||||
SCmpLeU32,
|
||||
SCmpLgU64,
|
||||
|
||||
VNop,
|
||||
VMovB32,
|
||||
VMovreldB32,
|
||||
VMovrelsB32,
|
||||
VReadfirstlaneB32,
|
||||
VReadlaneB32,
|
||||
VWritelaneB32,
|
||||
VPermlane16B32,
|
||||
VPermlanex16B32,
|
||||
VCubeidF32,
|
||||
VCubescF32,
|
||||
VCubetcF32,
|
||||
VCubemaF32,
|
||||
VCndmaskB32,
|
||||
VDot2cF32F16,
|
||||
VCvtF32I32,
|
||||
VCvtF32U32,
|
||||
VCvtU32F32,
|
||||
VCvtI32F32,
|
||||
VCvtF16F32,
|
||||
VCvtF32F16,
|
||||
VCvtF16U16,
|
||||
VCvtU16F16,
|
||||
VCvtF16I16,
|
||||
VCvtI16F16,
|
||||
VCvtRpiI32F32,
|
||||
VCvtFlrI32F32,
|
||||
VCvtOffF32I4,
|
||||
VCvtF32Ubyte0,
|
||||
VCvtF32Ubyte1,
|
||||
VCvtF32Ubyte2,
|
||||
VCvtF32Ubyte3,
|
||||
VRcpF32,
|
||||
VFractF32,
|
||||
VTruncF32,
|
||||
VCeilF32,
|
||||
VRndneF32,
|
||||
VFloorF32,
|
||||
VExpF32,
|
||||
VLogF32,
|
||||
VRsqF32,
|
||||
VSqrtF32,
|
||||
VRcpF16,
|
||||
VSqrtF16,
|
||||
VRsqF16,
|
||||
VLogF16,
|
||||
VExpF16,
|
||||
VFloorF16,
|
||||
VCeilF16,
|
||||
VTruncF16,
|
||||
VRndneF16,
|
||||
VSinF32,
|
||||
VCosF32,
|
||||
VNotB32,
|
||||
VBfrevB32,
|
||||
VFfbhU32,
|
||||
VFfblB32,
|
||||
VAddF32,
|
||||
VSubF32,
|
||||
VSubrevF32,
|
||||
VMulF32,
|
||||
VMacF32,
|
||||
VMadmkF32,
|
||||
VMadakF32,
|
||||
VMinF32,
|
||||
VMaxF32,
|
||||
VAddF16,
|
||||
VSubF16,
|
||||
VSubrevF16,
|
||||
VMulF16,
|
||||
VFmacF16,
|
||||
VFmamkF16,
|
||||
VFmaakF16,
|
||||
VMinI32,
|
||||
VMaxI32,
|
||||
VMulI32I24,
|
||||
VMulU32U24,
|
||||
VMulLoU32,
|
||||
VMulHiU32,
|
||||
VMulLoI32,
|
||||
VMulHiI32,
|
||||
VCvtPkrtzF16F32,
|
||||
VCvtPkU8F32,
|
||||
VMadF32,
|
||||
VMadI32I24,
|
||||
VMadU32U24,
|
||||
VMadU64U32,
|
||||
VFmaF32,
|
||||
VFmaF16,
|
||||
VPackB32F16,
|
||||
VBfeU32,
|
||||
VBfeI32,
|
||||
VBfiB32,
|
||||
VAlignbitB32,
|
||||
VMin3F32,
|
||||
VMin3I32,
|
||||
VMin3U32,
|
||||
VMin3F16,
|
||||
VMax3F32,
|
||||
VMax3I32,
|
||||
VMax3U32,
|
||||
VMax3F16,
|
||||
VMed3F32,
|
||||
VMed3I32,
|
||||
VMed3U32,
|
||||
VMed3F16,
|
||||
VSadU32,
|
||||
VAdd3U32,
|
||||
VLshlAddU32,
|
||||
VAddLshlU32,
|
||||
VXadU32,
|
||||
VLshlOrB32,
|
||||
VAndOrB32,
|
||||
VOr3B32,
|
||||
VXor3B32,
|
||||
VAddI32,
|
||||
VSubI32,
|
||||
VSubrevI32,
|
||||
VBfmB32,
|
||||
VLdexpF32,
|
||||
VCvtPknormI16F32,
|
||||
VCvtPknormU16F32,
|
||||
VCvtPkU16U32,
|
||||
VPkMadI16,
|
||||
VPkMulLoU16,
|
||||
VPkAddI16,
|
||||
VPkSubI16,
|
||||
VPkLshlrevB16,
|
||||
VPkLshrrevB16,
|
||||
VPkAshrrevI16,
|
||||
VPkMaxI16,
|
||||
VPkMinI16,
|
||||
VPkMadU16,
|
||||
VPkAddF16,
|
||||
VPkMulF16,
|
||||
VPkMinF16,
|
||||
VPkMaxF16,
|
||||
VPkFmaF16,
|
||||
VPkFmacF16,
|
||||
VPkAddU16,
|
||||
VPkSubU16,
|
||||
VPkMaxU16,
|
||||
VPkMinU16,
|
||||
VMadMixloF16,
|
||||
VMadMixhiF16,
|
||||
VAddNcU32,
|
||||
VAddcU32,
|
||||
VSubNcU32,
|
||||
VSubrevNcU32,
|
||||
VAddNcU16,
|
||||
VSubNcU16,
|
||||
VMaxU16,
|
||||
VMaxI16,
|
||||
VMinU16,
|
||||
VMinI16,
|
||||
VAddNcI16,
|
||||
VSubNcI16,
|
||||
VAndB32,
|
||||
VOrB32,
|
||||
VXorB32,
|
||||
VXnorB32,
|
||||
VLshlB32,
|
||||
VLshlrevB32,
|
||||
VLshrB32,
|
||||
VLshrrevB32,
|
||||
VAshrI32,
|
||||
VAshrrevI32,
|
||||
VLshlrevB16,
|
||||
VLshrrevB16,
|
||||
VAshrrevI16,
|
||||
VBcntU32B32,
|
||||
VMbcntLoU32B32,
|
||||
VMbcntHiU32B32,
|
||||
VMinU32,
|
||||
VMaxU32,
|
||||
VMaxF16,
|
||||
VMinF16,
|
||||
VCmpFF32,
|
||||
VCmpLtF32,
|
||||
VCmpEqF32,
|
||||
VCmpLeF32,
|
||||
VCmpGtF32,
|
||||
VCmpLgF32,
|
||||
VCmpGeF32,
|
||||
VCmpOF32,
|
||||
VCmpUF32,
|
||||
VCmpNgeF32,
|
||||
VCmpNlgF32,
|
||||
VCmpNgtF32,
|
||||
VCmpNleF32,
|
||||
VCmpNeqF32,
|
||||
VCmpNltF32,
|
||||
VCmpTruF32,
|
||||
VCmpxLtF32,
|
||||
VCmpxEqF32,
|
||||
VCmpxLeF32,
|
||||
VCmpxGtF32,
|
||||
VCmpxLgF32,
|
||||
VCmpxGeF32,
|
||||
VCmpxNgeF32,
|
||||
VCmpxNlgF32,
|
||||
VCmpxNgtF32,
|
||||
VCmpxNleF32,
|
||||
VCmpxNeqF32,
|
||||
VCmpxNltF32,
|
||||
VCmpFI32,
|
||||
VCmpLtI32,
|
||||
VCmpEqI32,
|
||||
VCmpLeI32,
|
||||
VCmpGtI32,
|
||||
VCmpNeI32,
|
||||
VCmpGeI32,
|
||||
VCmpTI32,
|
||||
VCmpClassF32,
|
||||
VCmpLtI16,
|
||||
VCmpEqI16,
|
||||
VCmpLeI16,
|
||||
VCmpGtI16,
|
||||
VCmpNeI16,
|
||||
VCmpGeI16,
|
||||
VCmpLtF16,
|
||||
VCmpEqF16,
|
||||
VCmpLeF16,
|
||||
VCmpGtF16,
|
||||
VCmpLgF16,
|
||||
VCmpGeF16,
|
||||
VCmpNeqF16,
|
||||
VCmpxLtF16,
|
||||
VCmpxEqF16,
|
||||
VCmpxLeF16,
|
||||
VCmpxGtF16,
|
||||
VCmpxGeF16,
|
||||
VCmpxNeqF16,
|
||||
VCmpxNltF16,
|
||||
VCmpxLtI32,
|
||||
VCmpxEqI32,
|
||||
VCmpxLeI32,
|
||||
VCmpxGtI32,
|
||||
VCmpxNeI32,
|
||||
VCmpxGeI32,
|
||||
VCmpLtU16,
|
||||
VCmpEqU16,
|
||||
VCmpLeU16,
|
||||
VCmpGtU16,
|
||||
VCmpNeU16,
|
||||
VCmpGeU16,
|
||||
VCmpFU32,
|
||||
VCmpLtU32,
|
||||
VCmpEqU32,
|
||||
VCmpLeU32,
|
||||
VCmpGtU32,
|
||||
VCmpNeU32,
|
||||
VCmpGeU32,
|
||||
VCmpTU32,
|
||||
VCmpNeU64,
|
||||
VCmpxLtU32,
|
||||
VCmpxEqU32,
|
||||
VCmpxLeU32,
|
||||
VCmpxGtU32,
|
||||
VCmpxNeU32,
|
||||
VCmpxGeU32,
|
||||
|
||||
SLoadDword,
|
||||
SLoadDwordx2,
|
||||
SLoadDwordx4,
|
||||
SLoadDwordx8,
|
||||
SLoadDwordx16,
|
||||
SBufferLoadDword,
|
||||
SBufferLoadDwordx2,
|
||||
SBufferLoadDwordx4,
|
||||
SBufferLoadDwordx8,
|
||||
SBufferLoadDwordx16,
|
||||
BufferLoadFormatX,
|
||||
BufferLoadFormatXy,
|
||||
BufferLoadFormatXyz,
|
||||
BufferLoadFormatXyzw,
|
||||
BufferStoreFormatX,
|
||||
BufferStoreFormatXy,
|
||||
BufferStoreFormatXyz,
|
||||
BufferStoreFormatXyzw,
|
||||
BufferLoadUbyte,
|
||||
BufferLoadSbyte,
|
||||
BufferLoadUshort,
|
||||
BufferLoadSshort,
|
||||
BufferLoadDword,
|
||||
BufferLoadDwordx2,
|
||||
BufferLoadDwordx3,
|
||||
BufferLoadDwordx4,
|
||||
BufferStoreByte,
|
||||
BufferStoreShort,
|
||||
BufferStoreDword,
|
||||
BufferStoreDwordx2,
|
||||
BufferStoreDwordx3,
|
||||
BufferStoreDwordx4,
|
||||
TBufferLoadFormatX,
|
||||
TBufferLoadFormatXy,
|
||||
TBufferLoadFormatXyz,
|
||||
TBufferLoadFormatXyzw,
|
||||
TBufferStoreFormatX,
|
||||
TBufferStoreFormatXy,
|
||||
TBufferStoreFormatXyz,
|
||||
TBufferStoreFormatXyzw,
|
||||
BufferAtomicSwap,
|
||||
BufferAtomicAdd,
|
||||
BufferAtomicSub,
|
||||
BufferAtomicSMin,
|
||||
BufferAtomicUMin,
|
||||
BufferAtomicSMax,
|
||||
BufferAtomicUMax,
|
||||
BufferAtomicAnd,
|
||||
BufferAtomicOr,
|
||||
BufferAtomicXor,
|
||||
FlatLoadUbyte,
|
||||
FlatLoadSbyte,
|
||||
FlatLoadUshort,
|
||||
FlatLoadSshort,
|
||||
FlatLoadDword,
|
||||
FlatLoadDwordx2,
|
||||
FlatLoadDwordx3,
|
||||
FlatLoadDwordx4,
|
||||
FlatStoreByte,
|
||||
FlatStoreShort,
|
||||
FlatStoreDword,
|
||||
FlatStoreDwordx2,
|
||||
FlatStoreDwordx3,
|
||||
FlatStoreDwordx4,
|
||||
DsAddU32,
|
||||
DsAddRtnU32,
|
||||
DsSubU32,
|
||||
DsSubRtnU32,
|
||||
DsMinI32,
|
||||
DsMinRtnI32,
|
||||
DsMaxI32,
|
||||
DsMaxRtnI32,
|
||||
DsMinU32,
|
||||
DsMinRtnU32,
|
||||
DsMaxU32,
|
||||
DsMaxRtnU32,
|
||||
DsAndB32,
|
||||
DsAndRtnB32,
|
||||
DsOrB32,
|
||||
DsOrRtnB32,
|
||||
DsXorB32,
|
||||
DsXorRtnB32,
|
||||
DsWrxchgRtnB32,
|
||||
DsMinF32,
|
||||
DsMaxF32,
|
||||
DsSwizzleB32,
|
||||
DsConsume,
|
||||
DsAppend,
|
||||
DsReadSbyte,
|
||||
DsReadUbyte,
|
||||
DsReadSshort,
|
||||
DsReadUshort,
|
||||
DsRead2B32,
|
||||
DsReadB32,
|
||||
DsReadB64,
|
||||
DsRead2B64,
|
||||
DsRead2St64B64,
|
||||
DsReadB96,
|
||||
DsReadB128,
|
||||
DsWriteByte,
|
||||
DsWriteShort,
|
||||
DsWrite2B32,
|
||||
DsWrite2St64B32,
|
||||
DsWrite2B64,
|
||||
DsWrite2St64B64,
|
||||
DsWriteB32,
|
||||
DsWriteB64,
|
||||
DsWriteB96,
|
||||
DsWriteB128,
|
||||
DsWriteAddtidB32,
|
||||
DsReadAddtidB32,
|
||||
ImageGetResinfo,
|
||||
ImageGetLod,
|
||||
ImageLoad,
|
||||
ImageLoadMip,
|
||||
ImageStore,
|
||||
ImageStoreMip,
|
||||
ImageAtomicAdd,
|
||||
ImageAtomicUMin,
|
||||
ImageAtomicUMax,
|
||||
ImageAtomicAnd,
|
||||
ImageAtomicOr,
|
||||
ImageAtomicXor,
|
||||
ImageSample,
|
||||
ImageGather4Lz,
|
||||
ImageGather4C,
|
||||
ImageGather4CLz,
|
||||
ImageGather4LzO,
|
||||
ImageGather4CO,
|
||||
ImageGather4CLzO,
|
||||
ImageGather4H,
|
||||
VInterpP1F32,
|
||||
VInterpP2F32,
|
||||
VInterpMovF32,
|
||||
|
||||
SNop,
|
||||
SWaitcnt,
|
||||
SBarrier,
|
||||
SBranch,
|
||||
SCbranchScc0,
|
||||
SCbranchScc1,
|
||||
SCbranchVccz,
|
||||
SCbranchVccnz,
|
||||
SCbranchExecz,
|
||||
SCbranchExecnz,
|
||||
SSendmsg,
|
||||
SSetregB32,
|
||||
SSleep,
|
||||
STtraceData,
|
||||
SInstPrefetch,
|
||||
SEndpgm,
|
||||
Exp
|
||||
};
|
||||
|
||||
enum class OperandKind {
|
||||
Unknown,
|
||||
LiteralConstant,
|
||||
IntegerInlineConstant,
|
||||
FloatInlineConstant,
|
||||
Sgpr,
|
||||
VccLo,
|
||||
VccHi,
|
||||
VccZ,
|
||||
ExecLo,
|
||||
ExecHi,
|
||||
ExecZ,
|
||||
Scc,
|
||||
M0,
|
||||
PopsExitingWaveId,
|
||||
Null,
|
||||
Vgpr,
|
||||
};
|
||||
|
||||
enum ImageSampleFlag : uint32_t {
|
||||
ImageSampleFlagLod = 1u << 0u,
|
||||
ImageSampleFlagBias = 1u << 1u,
|
||||
ImageSampleFlagDerivative = 1u << 2u,
|
||||
ImageSampleFlagCompare = 1u << 3u,
|
||||
ImageSampleFlagOffset = 1u << 4u,
|
||||
ImageSampleFlagLevelZero = 1u << 5u,
|
||||
ImageSampleFlagLodClamp = 1u << 6u,
|
||||
ImageSampleFlagA16 = 1u << 7u,
|
||||
ImageSampleFlagCd = 1u << 8u,
|
||||
ImageSampleFlagGatherHorizontal = 1u << 9u,
|
||||
};
|
||||
|
||||
enum class ImageDimension : uint32_t {
|
||||
Unknown,
|
||||
Dim1D,
|
||||
Dim1DArray,
|
||||
Dim2D,
|
||||
Dim3D,
|
||||
Dim2DArray,
|
||||
};
|
||||
|
||||
constexpr uint32_t MaxInstructionRawWords = 5u;
|
||||
constexpr uint32_t MaxImageNsaAddressComponents = 12u;
|
||||
|
||||
struct Operand {
|
||||
OperandKind kind = OperandKind::Unknown;
|
||||
uint32_t value = 0;
|
||||
int32_t signed_val = 0;
|
||||
float float_val = 0.0f;
|
||||
uint32_t reg = 0;
|
||||
uint32_t sdwa_sel = 6;
|
||||
uint32_t sdwa_dst_unused = 0;
|
||||
uint32_t omod = 0;
|
||||
uint32_t dpp_ctrl = 0;
|
||||
uint32_t dpp_row_mask = 0xf;
|
||||
uint32_t dpp_bank_mask = 0xf;
|
||||
bool sdwa_sext = false;
|
||||
bool dpp_fetch_inactive = false;
|
||||
bool dpp_bound_ctrl = false;
|
||||
bool op_sel = false;
|
||||
bool op_sel_hi = false;
|
||||
bool negate = false;
|
||||
bool negate_hi = false;
|
||||
bool absolute = false;
|
||||
bool clamp = false;
|
||||
bool dpp = false;
|
||||
};
|
||||
|
||||
struct Instruction {
|
||||
uint32_t pc = 0;
|
||||
uint32_t word = 0;
|
||||
uint32_t word_count = 1;
|
||||
uint32_t raw[MaxInstructionRawWords] = {};
|
||||
uint32_t raw_count = 1;
|
||||
Family family = Family::Unknown;
|
||||
uint32_t opcode_id = 0;
|
||||
Opcode opcode = Opcode::Unknown;
|
||||
Operand dst;
|
||||
Operand dst2;
|
||||
Operand src0;
|
||||
Operand src1;
|
||||
Operand src2;
|
||||
Operand src3;
|
||||
uint32_t src_count = 0;
|
||||
uint32_t offset = 0;
|
||||
uint32_t secondary_offset = 0;
|
||||
uint32_t dmask = 0;
|
||||
uint32_t data_dwords = 1;
|
||||
uint32_t data_bits = 32;
|
||||
uint32_t data_format = 0;
|
||||
uint32_t number_format = 0;
|
||||
uint32_t image_sample_flags = 0;
|
||||
ImageDimension image_dimension = ImageDimension::Unknown;
|
||||
uint32_t image_address_components = 0;
|
||||
uint32_t image_nsa_dwords = 0;
|
||||
uint32_t image_nsa_addr[MaxImageNsaAddressComponents] = {};
|
||||
uint32_t memory_segment = 0;
|
||||
bool data_signed = false;
|
||||
bool typed = false;
|
||||
bool formatted = false;
|
||||
bool gds = false;
|
||||
bool glc = false;
|
||||
bool slc = false;
|
||||
bool idxen = false;
|
||||
bool offen = false;
|
||||
int32_t branch_offset = 0;
|
||||
uint32_t branch_target = 0;
|
||||
struct {
|
||||
uint32_t target = 0;
|
||||
uint32_t en = 0;
|
||||
bool done = false;
|
||||
bool compr = false;
|
||||
bool vm = false;
|
||||
} exp;
|
||||
std::string unsupported_reason;
|
||||
};
|
||||
|
||||
struct Program {
|
||||
std::span<const uint32_t> code;
|
||||
std::vector<Instruction> instructions;
|
||||
};
|
||||
|
||||
bool DecodeProgram(std::span<const uint32_t> code, Program& program, std::string* error);
|
||||
|
||||
bool DecodeScalarSource(uint32_t code, uint32_t pc, Operand& operand, std::string* error);
|
||||
bool DecodeScalarDestination(uint32_t code, uint32_t pc, Operand& operand, std::string* error);
|
||||
bool DecodeVectorGpr(uint32_t reg, Operand& operand, std::string* error);
|
||||
bool ReadLiteralOperands(std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error);
|
||||
void SetRawWords(Instruction& inst, std::span<const uint32_t> code, uint32_t word_index,
|
||||
uint32_t word_count);
|
||||
void SetUnsupported(Instruction& inst, Family family, uint32_t opcode_id, const char* reason);
|
||||
std::string FamilyToString(Family family);
|
||||
std::string OpcodeToString(Opcode opcode);
|
||||
std::string OperandToString(const Operand& operand);
|
||||
const char* ImageDimensionToString(ImageDimension dimension);
|
||||
std::string InstructionToString(const Instruction& inst);
|
||||
std::string ProgramToString(const Program& program);
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Decoder
|
||||
|
||||
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_RECOMPILER_SHADERDECODER_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,23 @@
|
||||
#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_RECOMPILER_VECTORALUOPS_H_
|
||||
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_RECOMPILER_VECTORALUOPS_H_
|
||||
|
||||
#include "graphics/shader/recompiler/decompiler/ShaderDecoder.h"
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Decoder {
|
||||
|
||||
bool DecodeVop2(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error);
|
||||
bool DecodeVop1(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error);
|
||||
bool DecodeVopc(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error);
|
||||
bool DecodeVop3(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index, Instruction& inst,
|
||||
std::string* error);
|
||||
bool DecodeVop3p(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
Instruction& inst, std::string* error);
|
||||
bool DecodeVintrp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index,
|
||||
Instruction& inst, std::string* error);
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Decoder
|
||||
|
||||
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_RECOMPILER_VECTORALUOPS_H_ */
|
||||
Reference in New Issue
Block a user