222 lines
6.7 KiB
C++
222 lines
6.7 KiB
C++
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
#include "common/assert.h"
|
|
#include <cstdlib>
|
|
#include <sys/stat.h>
|
|
#include <vector>
|
|
|
|
enum class Opcode {
|
|
#define INST(name, cute, encode) name,
|
|
#include "shader_recompiler/frontend/maxwell/maxwell.inc"
|
|
#undef INST
|
|
};
|
|
|
|
consteval std::pair<u64, u64> MaskValueFromEncoding(const char data[20]) noexcept {
|
|
u64 mask = 0, value = 0, bit = u64(1) << 63;
|
|
for (int i = 0; i < 20; ++i)
|
|
switch (data[i]) {
|
|
case '0':
|
|
mask |= bit;
|
|
bit >>= 1;
|
|
break;
|
|
case '1':
|
|
mask |= bit;
|
|
value |= bit;
|
|
bit >>= 1;
|
|
break;
|
|
case '-':
|
|
bit >>= 1;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return { mask, value };
|
|
}
|
|
|
|
Opcode Decode(u64 insn) {
|
|
#define INST(name, cute, encode) \
|
|
if (auto const p = MaskValueFromEncoding(encode); (insn & p.first) == p.second) \
|
|
return Opcode::name;
|
|
#include "shader_recompiler/frontend/maxwell/maxwell.inc"
|
|
#undef INST
|
|
ASSERT_MSG(false, "Invalid insn 0x{:016x}", insn);
|
|
return Opcode::NOP;
|
|
}
|
|
|
|
const char* NameOf(Opcode opcode) {
|
|
constexpr const char* NAME_TABLE[] = {
|
|
#define INST(name, cute, encode) cute,
|
|
#include "shader_recompiler/frontend/maxwell/maxwell.inc"
|
|
#undef INST
|
|
};
|
|
ASSERT_MSG(size_t(opcode) < sizeof(NAME_TABLE) / sizeof(NAME_TABLE[0]), "Invalid opcode with raw value {}", int(opcode));
|
|
return NAME_TABLE[size_t(opcode)];
|
|
}
|
|
|
|
namespace Shader::Maxwell {
|
|
std::string_view SpecialRegGetName(size_t i) {
|
|
switch (i) {
|
|
case 0: return "SR_LANEID";
|
|
case 1: return "SR_CLOCK";
|
|
case 2: return "SR_VIRTCFG";
|
|
case 3: return "SR_VIRTID";
|
|
case 4: return "SR_PM0";
|
|
case 5: return "SR_PM1";
|
|
case 6: return "SR_PM2";
|
|
case 7: return "SR_PM3";
|
|
case 8: return "SR_PM4";
|
|
case 9: return "SR_PM5";
|
|
case 10: return "SR_PM6";
|
|
case 11: return "SR_PM7";
|
|
case 12: return "SR_?";
|
|
case 13: return "SR_?";
|
|
case 14: return "SR_?";
|
|
case 15: return "SR_ORDERING_TICKET";
|
|
case 16: return "SR_PRIM_TYPE";
|
|
case 17: return "SR_INVOCATION_ID";
|
|
case 18: return "SR_Y_DIRECTION";
|
|
case 19: return "SR_THREAD_KILL";
|
|
case 20: return "SM_SHADER_TYPE";
|
|
case 21: return "SR_DIRECTCBEWRITEADDRESSLOW";
|
|
case 22: return "SR_DIRECTCBEWRITEADDRESSHIGH";
|
|
case 23: return "SR_DIRECTCBEWRITEENABLED";
|
|
case 24: return "SR_MACHINE_ID_0";
|
|
case 25: return "SR_MACHINE_ID_1";
|
|
case 26: return "SR_MACHINE_ID_2";
|
|
case 27: return "SR_MACHINE_ID_3";
|
|
case 28: return "SR_AFFINITY";
|
|
case 29: return "SR_INVOCATION_INFO";
|
|
case 30: return "SR_WSCALEFACTOR_XY";
|
|
case 31: return "SR_WSCALEFACTOR_Z";
|
|
case 32: return "SR_TID";
|
|
case 33: return "SR_TID_X";
|
|
case 34: return "SR_TID_Y";
|
|
case 35: return "SR_TID_Z";
|
|
case 36: return "SR_CTA_PARAM";
|
|
case 37: return "SR_CTAID_X";
|
|
case 38: return "SR_CTAID_Y";
|
|
case 39: return "SR_CTAID_Z";
|
|
case 40: return "SR_NTID";
|
|
case 41: return "SR_CirQueueIncrMinusOne";
|
|
case 42: return "SR_NLATC";
|
|
case 43: return "SR_?";
|
|
case 44: return "SR_SM_SPA_VERSION";
|
|
case 45: return "SR_MULTIPASSSHADERINFO";
|
|
case 46: return "SR_LWINHI";
|
|
case 47: return "SR_SWINHI";
|
|
case 48: return "SR_SWINLO";
|
|
case 49: return "SR_SWINSZ";
|
|
case 50: return "SR_SMEMSZ";
|
|
case 51: return "SR_SMEMBANKS";
|
|
case 52: return "SR_LWINLO";
|
|
case 53: return "SR_LWINSZ";
|
|
case 54: return "SR_LMEMLOSZ";
|
|
case 55: return "SR_LMEMHIOFF";
|
|
case 56: return "SR_EQMASK";
|
|
case 57: return "SR_LTMASK";
|
|
case 58: return "SR_LEMASK";
|
|
case 59: return "SR_GTMASK";
|
|
case 60: return "SR_GEMASK";
|
|
case 61: return "SR_REGALLOC";
|
|
case 62: return "SR_BARRIERALLOC";
|
|
case 63: return "SR_?";
|
|
case 64: return "SR_GLOBALERRORSTATUS";
|
|
case 65: return "SR_?";
|
|
case 66: return "SR_WARPERRORSTATUS";
|
|
case 67: return "SR_WARPERRORSTATUSCLEAR";
|
|
case 68: return "SR_?";
|
|
case 69: return "SR_?";
|
|
case 70: return "SR_?";
|
|
case 71: return "SR_?";
|
|
case 72: return "SR_PM_HI0";
|
|
case 73: return "SR_PM_HI1";
|
|
case 74: return "SR_PM_HI2";
|
|
case 75: return "SR_PM_HI3";
|
|
case 76: return "SR_PM_HI4";
|
|
case 77: return "SR_PM_HI5";
|
|
case 78: return "SR_PM_HI6";
|
|
case 79: return "SR_PM_HI7";
|
|
case 80: return "SR_CLOCKLO";
|
|
case 81: return "SR_CLOCKHI";
|
|
case 82: return "SR_GLOBALTIMERLO";
|
|
case 83: return "SR_GLOBALTIMERHI";
|
|
case 84: return "SR_?";
|
|
case 85: return "SR_?";
|
|
case 86: return "SR_?";
|
|
case 87: return "SR_?";
|
|
case 88: return "SR_?";
|
|
case 89: return "SR_?";
|
|
case 90: return "SR_?";
|
|
case 91: return "SR_?";
|
|
case 92: return "SR_?";
|
|
case 93: return "SR_?";
|
|
case 94: return "SR_?";
|
|
case 95: return "SR_?";
|
|
case 96: return "SR_HWTASKID";
|
|
case 97: return "SR_CIRCULARQUEUEENTRYINDEX";
|
|
case 98: return "SR_CIRCULARQUEUEENTRYADDRESSLOW";
|
|
case 99: return "SR_CIRCULARQUEUEENTRYADDRESSHIGH";
|
|
default: return "SR_??"; }
|
|
}
|
|
}
|
|
#include "generated.cpp"
|
|
|
|
int DisasReferenceImpl(int argc, char *argv[]) {
|
|
std::vector<uint64_t> code;
|
|
FILE *fp = fopen(argv[1], "rb");
|
|
if (fp != NULL) {
|
|
struct stat st;
|
|
fstat(fileno(fp), &st);
|
|
auto const words = (size_t(st.st_size) / sizeof(uint64_t));
|
|
code.resize(words + 1);
|
|
fread(code.data(), sizeof(uint64_t), words, fp);
|
|
fclose(fp);
|
|
}
|
|
for (size_t i = 0; i < code.size(); ++i) {
|
|
printf("%016lx\t%-40s\n", code[i]
|
|
, Shader::Maxwell::DissasemblyFormat(code[i]).data()
|
|
);
|
|
}
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
int DisasShaderRecompilerImpl(int argc, char *argv[]) {
|
|
std::vector<u64> code;
|
|
FILE *fp = fopen(argv[1], "rb");
|
|
if (fp != NULL) {
|
|
struct stat st;
|
|
fstat(fileno(fp), &st);
|
|
auto const words = (size_t(st.st_size) / sizeof(u64));
|
|
code.resize(words + 1);
|
|
fread(code.data(), sizeof(u64), words, fp);
|
|
fclose(fp);
|
|
}
|
|
|
|
for (size_t i = 0; i < code.size(); ++i) {
|
|
auto const opcode = Decode(code[i]);
|
|
printf("%016lx\t%s\n", code[i], NameOf(opcode));
|
|
}
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
if (argc < 2) {
|
|
printf(
|
|
"usage: %s [input file] [-n/i]\n"
|
|
"Specify -n to use a disassembler that is NOT tied to the shader recompiler\n"
|
|
"aka. a reference disassembler\n"
|
|
, argv[0]);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
//DumpProgram
|
|
|
|
if (argc >= 3) {
|
|
if (::strcmp(argv[2], "-n") == 0 || ::strcmp(argv[2], "--new") == 0) {
|
|
return DisasReferenceImpl(argc, argv);
|
|
}
|
|
}
|
|
return DisasShaderRecompilerImpl(argc, argv);
|
|
}
|