aboutsummaryrefslogtreecommitdiff
path: root/tools/maxwell-disas/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/maxwell-disas/main.cpp')
-rw-r--r--tools/maxwell-disas/main.cpp221
1 files changed, 221 insertions, 0 deletions
diff --git a/tools/maxwell-disas/main.cpp b/tools/maxwell-disas/main.cpp
new file mode 100644
index 0000000000..0feee75824
--- /dev/null
+++ b/tools/maxwell-disas/main.cpp
@@ -0,0 +1,221 @@
+// 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);
+}