summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorPierre Bourdon <delroth@gmail.com>2014-08-03 21:52:08 -0700
committerPierre Bourdon <delroth@gmail.com>2014-08-03 21:52:08 -0700
commit6befa34b609797b4c48dd45b0f0a7adeba8d8a40 (patch)
tree869ff351cb9a9b4115518da6be8837b9846d9e67 /Source/Core
parent05a9f5b07abfbb41954b977652e7d11000ea9fae (diff)
parent0718937237db22d26e1b764b4733645c2b9f1562 (diff)
Merge pull request #647 from lioncash/disasm
Common: Introduce the new Gekko disassembler to Common.
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Common/CMakeLists.txt1
-rw-r--r--Source/Core/Common/Common.vcxproj4
-rw-r--r--Source/Core/Common/Common.vcxproj.filters2
-rw-r--r--Source/Core/Common/DebugInterface.h2
-rw-r--r--Source/Core/Common/GekkoDisassembler.cpp2299
-rw-r--r--Source/Core/Common/GekkoDisassembler.h152
-rw-r--r--Source/Core/Core/Debugger/PPCDebugInterface.cpp24
-rw-r--r--Source/Core/Core/Debugger/PPCDebugInterface.h2
-rw-r--r--Source/Core/Core/HW/DSPLLE/DSPDebugInterface.cpp7
-rw-r--r--Source/Core/Core/HW/DSPLLE/DSPDebugInterface.h3
-rw-r--r--Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp14
-rw-r--r--Source/Core/Core/PowerPC/Jit64/Jit.cpp7
-rw-r--r--Source/Core/Core/PowerPC/JitCommon/JitBase.cpp10
-rw-r--r--Source/Core/Core/PowerPC/PPCSymbolDB.cpp6
-rw-r--r--Source/Core/DolphinWX/Debugger/CodeView.cpp108
-rw-r--r--Source/Core/DolphinWX/Debugger/JitWindow.cpp7
-rw-r--r--Source/Core/DolphinWX/Debugger/RegisterView.cpp8
17 files changed, 2546 insertions, 110 deletions
diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt
index d5974ecca6..246b5da0e7 100644
--- a/Source/Core/Common/CMakeLists.txt
+++ b/Source/Core/Common/CMakeLists.txt
@@ -3,6 +3,7 @@ set(SRCS BreakPoints.cpp
ColorUtil.cpp
FileSearch.cpp
FileUtil.cpp
+ GekkoDisassembler.cpp
Hash.cpp
IniFile.cpp
MathUtil.cpp
diff --git a/Source/Core/Common/Common.vcxproj b/Source/Core/Common/Common.vcxproj
index 31d7bcaffd..106d925365 100644
--- a/Source/Core/Common/Common.vcxproj
+++ b/Source/Core/Common/Common.vcxproj
@@ -56,6 +56,7 @@
<ClInclude Include="FileUtil.h" />
<ClInclude Include="FixedSizeQueue.h" />
<ClInclude Include="FPURoundMode.h" />
+ <ClInclude Include="GekkoDisassembler.h" />
<ClInclude Include="Hash.h" />
<ClInclude Include="IniFile.h" />
<ClInclude Include="LinearDiskCache.h" />
@@ -94,6 +95,7 @@
<ClCompile Include="ExtendedTrace.cpp" />
<ClCompile Include="FileSearch.cpp" />
<ClCompile Include="FileUtil.cpp" />
+ <ClCompile Include="GekkoDisassembler.cpp" />
<ClCompile Include="Hash.cpp" />
<ClCompile Include="IniFile.cpp" />
<ClCompile Include="MathUtil.cpp" />
@@ -140,4 +142,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
-</Project>
+</Project> \ No newline at end of file
diff --git a/Source/Core/Common/Common.vcxproj.filters b/Source/Core/Common/Common.vcxproj.filters
index 1afbcaa15f..3bb9f14958 100644
--- a/Source/Core/Common/Common.vcxproj.filters
+++ b/Source/Core/Common/Common.vcxproj.filters
@@ -70,6 +70,7 @@
<ClInclude Include="Crypto\bn.h">
<Filter>Crypto</Filter>
</ClInclude>
+ <ClInclude Include="GekkoDisassembler.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="BreakPoints.cpp" />
@@ -115,6 +116,7 @@
</ClCompile>
<ClCompile Include="stdafx.cpp" />
<ClCompile Include="XSaveWorkaround.cpp" />
+ <ClCompile Include="GekkoDisassembler.cpp" />
</ItemGroup>
<ItemGroup>
<Text Include="CMakeLists.txt" />
diff --git a/Source/Core/Common/DebugInterface.h b/Source/Core/Common/DebugInterface.h
index 26e0a3e2ee..96b4eec275 100644
--- a/Source/Core/Common/DebugInterface.h
+++ b/Source/Core/Common/DebugInterface.h
@@ -9,7 +9,7 @@ protected:
virtual ~DebugInterface() {}
public:
- virtual void Disassemble(unsigned int /*address*/, char *dest, int /*max_size*/) {strcpy(dest, "NODEBUGGER");}
+ virtual std::string Disassemble(unsigned int /*address*/) { return "NODEBUGGER"; }
virtual void GetRawMemoryString(int /*memory*/, unsigned int /*address*/, char *dest, int /*max_size*/) {strcpy(dest, "NODEBUGGER");}
virtual int GetInstructionSize(int /*instruction*/) {return 1;}
virtual bool IsAlive() {return true;}
diff --git a/Source/Core/Common/GekkoDisassembler.cpp b/Source/Core/Common/GekkoDisassembler.cpp
new file mode 100644
index 0000000000..464d1cb4f5
--- /dev/null
+++ b/Source/Core/Common/GekkoDisassembler.cpp
@@ -0,0 +1,2299 @@
+/* $VER: ppc_disasm.c V1.5 (27.05.2009)
+ *
+ * Disassembler module for the PowerPC microprocessor family
+ * Copyright (c) 1998-2001,2009,2011 Frank Wille
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Modified for use with Dolphin
+
+#include <string>
+
+#include "Common/CommonTypes.h"
+#include "Common/GekkoDisassembler.h"
+#include "Common/StringUtil.h"
+
+// version/revision
+#define PPCDISASM_VER 1
+#define PPCDISASM_REV 6
+
+// general defines
+#define PPCIDXMASK 0xfc000000
+#define PPCIDX2MASK 0x000007fe
+#define PPCDMASK 0x03e00000
+#define PPCAMASK 0x001f0000
+#define PPCBMASK 0x0000f800
+#define PPCCMASK 0x000007c0
+#define PPCMMASK 0x0000003e
+#define PPCCRDMASK 0x03800000
+#define PPCCRAMASK 0x001c0000
+#define PPCLMASK 0x00600000
+#define PPCOE 0x00000400
+#define PPCVRC 0x00000400
+#define PPCDST 0x02000000
+#define PPCSTRM 0x00600000
+
+#define PPCIDXSH 26
+#define PPCDSH 21
+#define PPCASH 16
+#define PPCBSH 11
+#define PPCCSH 6
+#define PPCMSH 1
+#define PPCCRDSH 23
+#define PPCCRASH 18
+#define PPCLSH 21
+#define PPCIDX2SH 1
+
+#define PPCGETIDX(x) (((x)&PPCIDXMASK)>>PPCIDXSH)
+#define PPCGETD(x) (((x)&PPCDMASK)>>PPCDSH)
+#define PPCGETA(x) (((x)&PPCAMASK)>>PPCASH)
+#define PPCGETB(x) (((x)&PPCBMASK)>>PPCBSH)
+#define PPCGETC(x) (((x)&PPCCMASK)>>PPCCSH)
+#define PPCGETM(x) (((x)&PPCMMASK)>>PPCMSH)
+#define PPCGETCRD(x) (((x)&PPCCRDMASK)>>PPCCRDSH)
+#define PPCGETCRA(x) (((x)&PPCCRAMASK)>>PPCCRASH)
+#define PPCGETL(x) (((x)&PPCLMASK)>>PPCLSH)
+#define PPCGETIDX2(x) (((x)&PPCIDX2MASK)>>PPCIDX2SH)
+#define PPCGETSTRM(x) (((x)&PPCSTRM)>>PPCDSH)
+
+
+static const char* trap_condition[32] = {
+ nullptr, "lgt", "llt", nullptr, "eq", "lge", "lle", nullptr,
+ "gt", nullptr, nullptr, nullptr, "ge", nullptr, nullptr, nullptr,
+ "lt", nullptr, nullptr, nullptr, "le", nullptr, nullptr, nullptr,
+ "ne", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr
+};
+
+static const char* cmpname[4] = {
+ "cmpw", "cmpd", "cmplw", "cmpld"
+};
+
+static const char* b_ext[4] = {
+ "", "l", "a", "la"
+};
+
+static const char* b_condition[8] = {
+ "ge", "le", "ne", "ns", "lt", "gt", "eq", "so"
+};
+
+static const char* b_decr[16] = {
+ "nzf", "zf", nullptr, nullptr, "nzt", "zt", nullptr, nullptr,
+ "nz", "z", nullptr, nullptr, "nz", "z", nullptr, nullptr
+};
+
+static const char* regsel[2] = {
+ "", "r"
+};
+
+static const char* oesel[2] = {
+ "", "o"
+};
+
+static const char* rcsel[2] = {
+ "", "."
+};
+
+static const char* ldstnames[24] = {
+ "lwz", "lwzu", "lbz", "lbzu", "stw", "stwu", "stb", "stbu", "lhz", "lhzu",
+ "lha", "lhau", "sth", "sthu", "lmw", "stmw", "lfs", "lfsu", "lfd", "lfdu",
+ "stfs", "stfsu", "stfd", "stfdu"
+};
+
+static const char* regnames[32] = {
+ "r0", "sp", "rtoc", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+ "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
+};
+
+// Initialize static class variables.
+u32* GekkoDisassembler::m_instr = nullptr;
+u32* GekkoDisassembler::m_iaddr = nullptr;
+std::string GekkoDisassembler::m_opcode = "";
+std::string GekkoDisassembler::m_operands = "";
+unsigned char GekkoDisassembler::m_type = 0;
+unsigned char GekkoDisassembler::m_flags = PPCF_ILLEGAL;
+unsigned short GekkoDisassembler::m_sreg = 0;
+u32 GekkoDisassembler::m_displacement = 0;
+
+
+static std::string spr_name(int i)
+{
+ switch (i)
+ {
+ case 1: return "XER";
+ case 8: return "LR";
+ case 9: return "CTR";
+ case 18: return "DSIR";
+ case 19: return "DAR";
+ case 22: return "DEC";
+ case 25: return "SDR1";
+ case 26: return "SRR0";
+ case 27: return "SRR1";
+ case 272: return "SPRG0";
+ case 273: return "SPRG1";
+ case 274: return "SPRG2";
+ case 275: return "SPRG3";
+ case 282: return "EAR";
+ case 287: return "PVR";
+ case 528: return "IBAT0U";
+ case 529: return "IBAT0L";
+ case 530: return "IBAT1U";
+ case 531: return "IBAT1L";
+ case 532: return "IBAT2U";
+ case 533: return "IBAT2L";
+ case 534: return "IBAT3U";
+ case 535: return "IBAT3L";
+ case 536: return "DBAT0U";
+ case 537: return "DBAT0L";
+ case 538: return "DBAT1U";
+ case 539: return "DBAT1L";
+ case 540: return "DBAT2U";
+ case 541: return "DBAT2L";
+ case 542: return "DBAT3U";
+ case 543: return "DBAT3L";
+ case 912: return "GQR0";
+ case 913: return "GQR1";
+ case 914: return "GQR2";
+ case 915: return "GQR3";
+ case 916: return "GQR4";
+ case 917: return "GQR5";
+ case 918: return "GQR6";
+ case 919: return "GQR7";
+ case 920: return "HID2";
+ case 921: return "WPAR";
+ case 922: return "DMA_U";
+ case 923: return "DMA_L";
+ case 924: return "ECID_U";
+ case 925: return "ECID_M";
+ case 926: return "ECID_L";
+ case 936: return "UMMCR0";
+ case 937: return "UPMC1";
+ case 938: return "UPMC2";
+ case 939: return "USIA";
+ case 940: return "UMMCR1";
+ case 941: return "UPMC3";
+ case 942: return "UPMC4";
+ case 943: return "USDA";
+ case 952: return "MMCR0";
+ case 953: return "PMC1";
+ case 954: return "PMC2";
+ case 955: return "SIA";
+ case 956: return "MMCR1";
+ case 957: return "PMC3";
+ case 958: return "PMC4";
+ case 959: return "SDA";
+ case 1008: return "HID0";
+ case 1009: return "HID1";
+ case 1010: return "IABR";
+ case 1011: return "HID4";
+ case 1013: return "DABR";
+ case 1017: return "L2CR";
+ case 1019: return "ICTC";
+ case 1020: return "THRM1";
+ case 1021: return "THRM2";
+ case 1022: return "THRM3";
+ }
+
+ return StringFromFormat("%d", i);
+}
+
+
+static u32 swapda(u32 w)
+{
+ return ((w & 0xfc00ffff) | ((w&PPCAMASK) << 5) | ((w&PPCDMASK) >> 5));
+}
+
+
+static u32 swapab(u32 w)
+{
+ return ((w & 0xffe007ff) | ((w&PPCBMASK) << 5) | ((w&PPCAMASK) >> 5));
+}
+
+
+void GekkoDisassembler::ill(u32 in)
+{
+ if (in == 0)
+ {
+ m_opcode = "";
+ m_operands = "---";
+ }
+ else
+ {
+ m_opcode = "(ill)";
+ m_operands = StringFromFormat("%08x", in);
+ }
+
+ m_flags |= PPCF_ILLEGAL;
+}
+
+// Generate immediate instruction operand.
+//
+// Type 0: D-mode, D,A,imm
+// Type 1: S-mode, A,S,imm
+// Type 2: S/D register is ignored (trap,cmpi)
+// Type 3: A register is ignored (li)
+std::string GekkoDisassembler::imm(u32 in, int uimm, int type, bool hex)
+{
+ int i = (int)(in & 0xffff);
+
+ m_type = PPCINSTR_IMM;
+
+ if (uimm == 0)
+ {
+ if (i > 0x7fff)
+ i -= 0x10000;
+ }
+ else
+ {
+ m_flags |= PPCF_UNSIGNED;
+ }
+ m_displacement = i;
+
+ switch (type)
+ {
+ case 0:
+ return StringFromFormat("%s, %s, %d", regnames[(int)PPCGETD(in)], regnames[(int)PPCGETA(in)], i);
+
+ case 1:
+ if (hex)
+ return StringFromFormat("%s, %s, 0x%.4X", regnames[(int)PPCGETA(in)], regnames[(int)PPCGETD(in)], i);
+ else
+ return StringFromFormat("%s, %s, %d", regnames[(int)PPCGETA(in)], regnames[(int)PPCGETD(in)], i);
+
+ case 2:
+ return StringFromFormat("%s, %d", regnames[(int)PPCGETA(in)], i);
+
+ case 3:
+ if (hex)
+ return StringFromFormat("%s, 0x%.4X", regnames[(int)PPCGETD(in)], i);
+ else
+ return StringFromFormat("%s, %d", regnames[(int)PPCGETD(in)], i);
+
+ default:
+ return StringFromFormat("%s", "imm(): Wrong type");
+ }
+}
+
+
+std::string GekkoDisassembler::ra_rb(u32 in)
+{
+ return StringFromFormat("%s, %s", regnames[(int)PPCGETA(in)], regnames[(int)PPCGETB(in)]);
+}
+
+
+std::string GekkoDisassembler::rd_ra_rb(u32 in, int mask)
+{
+ std::string result;
+
+ if (mask)
+ {
+ if (mask & 4)
+ result += StringFromFormat("%s, ", regnames[(int)PPCGETD(in)]);
+ if (mask & 2)
+ result += StringFromFormat("%s, ", regnames[(int)PPCGETA(in)]);
+ if (mask & 1)
+ result += StringFromFormat("%s, ", regnames[(int)PPCGETB(in)]);
+
+ size_t pos = result.rfind(", ");
+ if (pos != std::string::npos)
+ {
+ result.erase(pos, result.length() - pos);
+ }
+ }
+
+ return result;
+}
+
+
+std::string GekkoDisassembler::fd_ra_rb(u32 in, int mask)
+{
+ std::string result;
+
+ if (mask)
+ {
+ if (mask & 4)
+ result += StringFromFormat("f%d,", (int)PPCGETD(in));
+ if (mask & 2)
+ result += StringFromFormat("%s,", regnames[(int)PPCGETA(in)]);
+ if (mask & 1)
+ result += StringFromFormat("%s,", regnames[(int)PPCGETB(in)]);
+
+ // Drop the trailing comma
+ result.pop_back();
+ }
+
+ return result;
+}
+
+
+void GekkoDisassembler::trapi(u32 in, unsigned char dmode)
+{
+ const char* cnd = trap_condition[PPCGETD(in)];
+
+ if (cnd != nullptr)
+ {
+ m_flags |= dmode;
+ m_opcode = StringFromFormat("t%c%s", dmode ? 'd' : 'w', cnd);
+ m_operands = imm(in, 0, 2, false);
+ }
+ else
+ {
+ ill(in);
+ }
+}
+
+
+void GekkoDisassembler::cmpi(u32 in, int uimm)
+{
+ int i = (int)PPCGETL(in);
+
+ if (i < 2)
+ {
+ if (i != 0)
+ m_flags |= PPCF_64;
+
+ m_opcode = StringFromFormat("%si", cmpname[uimm * 2 + i]);
+
+ i = (int)PPCGETCRD(in);
+ if (i != 0)
+ {
+ m_operands += StringFromFormat("cr%c,", '0' + i);
+ }
+
+ m_operands += imm(in, uimm, 2, false);
+ }
+ else
+ {
+ ill(in);
+ }
+}
+
+
+void GekkoDisassembler::addi(u32 in, const std::string& ext)
+{
+ if ((in & 0x08000000) && !PPCGETA(in))
+ {
+ m_opcode = StringFromFormat("l%s", ext.c_str()); // li, lis
+
+ if (ext == "i")
+ m_operands = imm(in, 0, 3, false);
+ else
+ m_operands = imm(in, 1, 3, true);
+ }
+ else
+ {
+ m_opcode = StringFromFormat("%s%s", (in & 0x8000) ? "sub" : "add", ext.c_str());
+
+ if (in & 0x8000)
+ in = (in ^ 0xffff) + 1;
+
+ m_operands = imm(in, 1, 0, false);
+ }
+}
+
+// Build a branch instr. and return number of chars written to operand.
+size_t GekkoDisassembler::branch(u32 in, const char* bname, int aform, int bdisp)
+{
+ int bo = (int)PPCGETD(in);
+ int bi = (int)PPCGETA(in);
+ char y = (char)(bo & 1);
+ const char* ext = b_ext[aform * 2 + (int)(in & 1)];
+
+ if (bdisp < 0)
+ y ^= 1;
+ y = (y != 0) ? '+' : '-';
+
+ if (bo & 4)
+ {
+ // standard case - no decrement
+ if (bo & 16)
+ {
+ // branch always
+ if (PPCGETIDX(in) != 16)
+ {
+ m_opcode = StringFromFormat("b%s%s", bname, ext);
+ }
+ else
+ {
+ m_opcode = StringFromFormat("bc%s", ext);
+ m_operands = StringFromFormat("%d, %d", bo, bi);
+ }
+ }
+ else // Branch conditional
+ {
+ m_opcode = StringFromFormat("b%s%s%s%c", b_condition[((bo & 8) >> 1) + (bi & 3)], bname, ext, y);
+
+ if (bi >= 4)
+ {
+ m_operands = StringFromFormat("cr%d", bi >> 2);
+ }
+ }
+ }
+ else
+ {
+ // CTR is decremented and checked
+ m_opcode = StringFromFormat("bd%s%s%s%c", b_decr[bo >> 1], bname, ext, y);
+
+ if ((bo & 16) == 0)
+ {
+ m_operands = StringFromFormat("%d", bi);
+ }
+ }
+
+ return m_operands.length();
+}
+
+
+void GekkoDisassembler::bc(u32 in)
+{
+ unsigned int d = (int)(in & 0xfffc);
+
+ if (d & 0x8000)
+ d |= 0xffff0000;
+
+ branch(in, "", (in & 2) ? 1 : 0, d);
+
+ if (in & 2) // AA ?
+ m_operands = StringFromFormat("->0x%.8X", d);
+ else
+ m_operands = StringFromFormat("->0x%.8X", *m_iaddr + d);
+
+ m_type = PPCINSTR_BRANCH;
+ m_displacement = d;
+}
+
+
+void GekkoDisassembler::bli(u32 in)
+{
+ unsigned int d = (unsigned int)(in & 0x3fffffc);
+
+ if (d & 0x02000000)
+ d |= 0xfc000000;
+
+ m_opcode = StringFromFormat("b%s", b_ext[in & 3]);
+
+ if (in & 2) // AA ?
+ m_operands = StringFromFormat("->0x%.8X", d);
+ else
+ m_operands = StringFromFormat("->0x%.8X", *m_iaddr + d);
+
+ m_type = PPCINSTR_BRANCH;
+ m_displacement = d;
+}
+
+
+void GekkoDisassembler::mcrf(u32 in, char c)
+{
+ if ((in & 0x0063f801) == 0)
+ {
+ m_opcode = StringFromFormat("mcrf%c", c);
+ m_operands = StringFromFormat("cr%d, cr%d", (int)PPCGETCRD(in), (int)PPCGETCRA(in));
+ }
+ else
+ {
+ ill(in);
+ }
+}
+
+
+void GekkoDisassembler::crop(u32 in, const char* n1, const char* n2)
+{
+ int crd = (int)PPCGETD(in);
+ int cra = (int)PPCGETA(in);
+ int crb = (int)PPCGETB(in);
+
+ if ((in & 1) == 0)
+ {
+ m_opcode = StringFromFormat("cr%s", (cra == crb && n2) ? n2 : n1);
+ if (cra == crb && n2)
+ m_operands = StringFromFormat("%d, %d", crd, cra);
+ else
+ m_operands = StringFromFormat("%d, %d, %d", crd, cra, crb);
+ }
+ else
+ {
+ ill(in);
+ }
+}
+
+
+void GekkoDisassembler::nooper(u32 in, const char* name, unsigned char dmode)
+{
+ if (in & (PPCDMASK | PPCAMASK | PPCBMASK | 1))
+ {
+ ill(in);
+ }
+ else
+ {
+ m_flags |= dmode;
+ m_opcode = name;
+ }
+}
+
+void GekkoDisassembler::rlw(u32 in, const char* name, int i)
+{
+ int s = (int)PPCGETD(in);
+ int a = (int)PPCGETA(in);
+ int bsh = (int)PPCGETB(in);
+ int mb = (int)PPCGETC(in);
+ int me = (int)PPCGETM(in);
+
+ m_opcode = StringFromFormat("rlw%s%c", name, in & 1 ? '.' : '\0');
+ m_operands = StringFromFormat("%s, %s, %s%d, %d, %d (%08x)", regnames[a], regnames[s], regsel[i], bsh, mb, me, HelperRotateMask(bsh, mb, me));
+}
+
+
+void GekkoDisassembler::ori(u32 in, const char* name)
+{
+ m_opcode = name;
+ m_operands = imm(in, 1, 1, true);
+}
+
+
+void GekkoDisassembler::rld(u32 in, const char* name, int i)
+{
+ int s = (int)PPCGETD(in);
+ int a = (int)PPCGETA(in);
+ int bsh = i ? (int)PPCGETB(in) : (int)(((in & 2) << 4) + PPCGETB(in));
+ int m = (int)(in & 0x7e0) >> 5;
+
+ m_flags |= PPCF_64;
+ m_opcode = StringFromFormat("rld%s%c", name, in & 1 ? '.' : '\0');
+ m_operands = StringFromFormat("%s, %s, %s%d, %d", regnames[a], regnames[s], regsel[i], bsh, m);
+}
+
+
+void GekkoDisassembler::cmp(u32 in)
+{
+ int i = (int)PPCGETL(in);
+
+ if (i < 2)
+ {
+ if (i != 0)
+ m_flags |= PPCF_64;
+
+ m_opcode = cmpname[((in&PPCIDX2MASK) ? 2 : 0) + i];
+
+ i = (int)PPCGETCRD(in);
+ if (i != 0)
+ m_operands += StringFromFormat("cr%c,", '0' + i);
+
+ m_operands += ra_rb(in);
+ }
+ else
+ {
+ ill(in);
+ }
+}
+
+
+void GekkoDisassembler::trap(u32 in, unsigned char dmode)
+{
+ int to = (int)PPCGETD(in);
+ const char* cnd = trap_condition[to];
+
+ if (cnd != nullptr)
+ {
+ m_flags |= dmode;
+ m_opcode = StringFromFormat("t%c%s", dmode ? 'd' : 'w', cnd);
+ m_operands = ra_rb(in);
+ }
+ else
+ {
+ if (to == 31)
+ {
+ if (dmode)
+ {
+ m_flags |= dmode;
+ m_opcode = "td";
+ m_operands = "31,0,0";
+ }
+ else
+ {
+ m_opcode = "trap";
+ }
+ }
+ else
+ {
+ ill(in);
+ }
+ }
+}
+
+// Standard instruction: xxxx rD,rA,rB
+void GekkoDisassembler::dab(u32 in, const char* name, int mask, int smode, int chkoe, int chkrc, unsigned char dmode)
+{
+ if (chkrc >= 0 && ((in & 1) != (unsigned int)chkrc))
+ {
+ ill(in);
+ }
+ else
+ {
+ m_flags |= dmode;
+
+ // rA,rS,rB
+ if (smode)
+ in = swapda(in);
+
+ m_opcode = StringFromFormat("%s%s%s", name, oesel[chkoe && (in&PPCOE)], rcsel[(chkrc < 0) && (in & 1)]);
+ m_operands = rd_ra_rb(in, mask);
+ }
+}
+
+// Last operand is no register: xxxx rD,rA,NB
+void GekkoDisassembler::rrn(u32 in, const char* name, int smode, int chkoe, int chkrc, unsigned char dmode)
+{
+ if (chkrc >= 0 && ((in & 1) != (unsigned int)chkrc))
+ {
+ ill(in);
+ }
+ else
+ {
+ m_flags |= dmode;
+
+ // rA,rS,NB
+ if (smode)
+ in = swapda(in);
+
+ m_opcode = StringFromFormat("%s%s%s", name, oesel[chkoe && (in&PPCOE)], rcsel[(chkrc < 0) && (in & 1)]);
+
+ m_operands = rd_ra_rb(in, 6);
+ m_operands += StringFromFormat(",%d",(int)PPCGETB(in));
+ }
+}
+
+
+void GekkoDisassembler::mtcr(u32 in)
+{
+ int s = (int)PPCGETD(in);
+ int crm = (int)(in & 0x000ff000) >> 12;
+
+ if (in & 0x00100801)
+ {
+ ill(in);
+ }
+ else
+ {
+ m_opcode = StringFromFormat("mtcr%c", crm == 0xff ? '\0' : 'f');
+
+ if (crm != 0xff)
+ m_operands += StringFromFormat("0x%02x,", crm);
+
+ m_operands += regnames[s];
+ }
+}
+
+
+void GekkoDisassembler::msr(u32 in, int smode)
+{
+ int s = (int)PPCGETD(in);
+ int sr = (int)(in & 0x000f0000) >> 16;
+
+ if (in & 0x0010f801)
+ {
+ ill(in);
+ }
+ else
+ {
+ m_flags |= PPCF_SUPER;
+ m_opcode = StringFromFormat("m%csr", smode ? 't' : 'f');
+
+ if (smode)
+ m_operands = StringFromFormat("%d, %s", sr, regnames[s]);
+ else
+ m_operands = StringFromFormat("%s, %d", regnames[s], sr);
+ }
+}
+
+
+void GekkoDisassembler::mspr(u32 in, int smode)
+{
+ int d = (int)PPCGETD(in);
+ int spr = (int)((PPCGETB(in) << 5) + PPCGETA(in));
+ int fmt = 0;
+
+ if (in & 1)
+ {
+ ill(in);
+ }
+ else
+ {
+ if (spr != 1 && spr != 8 && spr != 9)
+ m_flags |= PPCF_SUPER;
+
+ const char* x;
+ switch (spr)
+ {
+ case 1:
+ x = "xer";
+ break;
+
+ case 8:
+ x = "lr";
+ break;
+
+ case 9:
+ x = "ctr";
+ break;
+
+ default:
+ x = "spr";
+ fmt = 1;
+ break;
+ }
+
+ m_opcode = StringFromFormat("m%c%s", smode ? 't' : 'f', x);
+
+ if (fmt)
+ {
+ if (smode)
+ m_operands = StringFromFormat("%s, %s", spr_name(spr).c_str(), regnames[d]);
+ else
+ m_operands = StringFromFormat("%s, %s", regnames[d], spr_name(spr).c_str());
+ }
+ else
+ {
+ m_operands = regnames[d];
+ }
+ }
+}
+
+
+void GekkoDisassembler::mtb(u32 in)
+{
+ int d = (int)PPCGETD(in);
+ int tbr = (int)((PPCGETB(in) << 5) + PPCGETA(in));
+
+ if (in & 1)
+ {
+ ill(in);
+ }
+ else
+ {
+ m_operands += regnames[d];
+
+ char x;
+ switch (tbr)
+ {
+ case 268:
+ x = 'l';
+ break;
+
+ case 269:
+ x = 'u';
+ break;
+
+ default:
+ x = '\0';
+ m_flags |= PPCF_SUPER;
+ m_operands += StringFromFormat(",%d", tbr);
+ break;
+ }
+
+ m_opcode = StringFromFormat("mftb%c", x);
+ }
+}
+
+
+void GekkoDisassembler::sradi(u32 in)
+{
+ int s = (int)PPCGETD(in);
+ int a = (int)PPCGETA(in);
+ int bsh = (int)(((in & 2) << 4) + PPCGETB(in));
+
+ m_flags |= PPCF_64;
+ m_opcode = StringFromFormat("sradi%c", in & 1 ? '.' : '\0');
+ m_operands = StringFromFormat("%s, %s, %d", regnames[a], regnames[s], bsh);
+}
+
+void GekkoDisassembler::ldst(u32 in, const char* name, char reg, unsigned char dmode)
+{
+ int s = (int)PPCGETD(in);
+ int a = (int)PPCGETA(in);
+ int d = (u32)(in & 0xffff);
+
+ m_type = PPCINSTR_LDST;
+ m_flags |= dmode;
+ m_sreg = (short)a;
+ // if (d >= 0x8000)
+ // d -= 0x10000;
+ m_displacement = (u32)d;
+ m_opcode = name;
+
+ if (reg == 'r')
+ {
+ m_operands = StringFromFormat("%s, %s (%s)", regnames[s], ldst_offs(d).c_str(), regnames[a]);
+ }
+ else
+ {
+ m_operands = StringFromFormat("%c%d, %s (%s)", reg, s, ldst_offs(d).c_str(), regnames[a]);
+ }
+}
+
+// Standard floating point instruction: xxxx fD,fA,fC,fB
+void GekkoDisassembler::fdabc(u32 in, const char* name, int mask, unsigned char dmode)
+{
+ int err = 0;
+
+ m_flags |= dmode;
+ m_opcode = StringFromFormat("f%s%s", name, rcsel[in & 1]);
+ m_operands += StringFromFormat("f%d,", (int)PPCGETD(in));
+
+ if (mask & 4)
+ m_operands += StringFromFormat("f%d,", (int)PPCGETA(in));
+ else
+ err |= (int)PPCGETA(in);
+
+ if (mask & 2)
+ m_operands += StringFromFormat("f%d,", (int)PPCGETC(in));
+ else if (PPCGETC(in))
+ err |= (int)PPCGETC(in);
+
+ if (mask & 1)
+ m_operands += StringFromFormat("f%d,", (int)PPCGETB(in));
+ else if (!(mask & 8))
+ err |= (int)PPCGETB(in);
+
+ // Drop the trailing comma
+ m_operands.pop_back();
+
+ if (err)
+ ill(in);
+}
+
+void GekkoDisassembler::fmr(u32 in)
+{
+ m_opcode = StringFromFormat("fmr%s", rcsel[in & 1]);
+ m_operands = StringFromFormat("f%d, f%d", (int)PPCGETD(in), (int)PPCGETB(in));
+}
+
+// Indexed float instruction: xxxx fD,rA,rB
+void GekkoDisassembler::fdab(u32 in, const char* name, int mask)
+{
+ m_opcode = name;
+ m_operands = fd_ra_rb(in, mask);
+}
+
+
+void GekkoDisassembler::fcmp(u32 in, char c)
+{
+ if (in & 0x00600001)
+ {
+ ill(in);
+ }
+ else
+ {
+ m_opcode = StringFromFormat("fcmp%c", c);
+ m_operands = StringFromFormat("cr%d,f%d,f%d", (int)PPCGETCRD(in), (int)PPCGETA(in), (int)PPCGETB(in));
+ }
+}
+
+
+void GekkoDisassembler::mtfsb(u32 in, int n)
+{
+ if (in & (PPCAMASK | PPCBMASK))
+ {
+ ill(in);
+ }
+ else
+ {
+ m_opcode = StringFromFormat("mtfsb%d%s", n, rcsel[in & 1]);
+ m_operands = StringFromFormat("%d", (int)PPCGETD(in));
+ }
+}
+
+
+// Paired instructions
+
+#define RA ((inst >> 16) & 0x1f)
+#define RB ((inst >> 11) & 0x1f)
+#define RC ((inst >> 6) & 0x1f)
+#define RD ((inst >> 21) & 0x1f)
+#define RS ((inst >> 21) & 0x1f)
+#define FA ((inst >> 16) & 0x1f)
+#define FB ((inst >> 11) & 0x1f)
+#define FC ((inst >> 6) & 0x1f)
+#define FD ((inst >> 21) & 0x1f)
+#define FS ((inst >> 21) & 0x1f)
+#define IMM (inst & 0xffff)
+#define UIMM (inst & 0xffff)
+#define OFS (inst & 0xffff)
+#define OPCD ((inst >> 26) & 0x3f)
+#define XO_10 ((inst >> 1) & 0x3ff)
+#define XO_9 ((inst >> 1) & 0x1ff)
+#define XO_5 ((inst >> 1) & 0x1f)
+#define Rc (inst & 1)
+#define SH ((inst >> 11) & 0x1f)
+#define MB ((inst >> 6) & 0x1f)
+#define ME ((inst >> 1) & 0x1f)
+#define OE ((inst >> 10) & 1)
+#define TO ((inst >> 21) & 0x1f)
+#define CRFD ((inst >> 23) & 0x7)
+#define CRFS ((inst >> 18) & 0x7)
+#define CRBD ((inst >> 21) & 0x1f)
+#define CRBA ((inst >> 16) & 0x1f)
+#define CRBB ((inst >> 11) & 0x1f)
+#define L ((inst >> 21) & 1)
+#define NB ((inst >> 11) & 0x1f)
+#define AA ((inst >> 1) & 1)
+#define LK (inst & 1)
+#define LI ((inst >> 2) & 0xffffff)
+#define BO ((inst >> 21) & 0x1f)
+#define BI ((inst >> 16) & 0x1f)
+#define BD ((inst >> 2) & 0x3fff)
+
+#define MTFSFI_IMM ((inst >> 12) & 0xf)
+#define FM ((inst >> 17) & 0xff)
+#define SR ((inst >> 16) & 0xf)
+#define SPR ((inst >> 11) & 0x3ff)
+#define TBR ((inst >> 11) & 0x3ff)
+#define CRM ((inst >> 12) & 0xff)
+
+
+void GekkoDisassembler::ps(u32 inst)
+{
+ switch ((inst >> 1) & 0x1F)
+ {
+ case 6:
+ m_opcode = "ps_lux";
+ m_operands = StringFromFormat("p%u, (r%u + r%u)", FD, RA, RB);
+ return;
+
+ case 18:
+ m_opcode = "ps_div";
+ m_operands = StringFromFormat("p%u, p%u/p%u", FD, FA, FB);
+ return;
+
+ case 20:
+ m_opcode = "ps_sub";
+ m_operands = StringFromFormat("p%u, p%u-p%u", FD, FA, FB);
+ return;
+
+ case 21:
+ m_opcode = "ps_add";
+ m_operands = StringFromFormat("p%u, p%u+p%u", FD, FA, FB);
+ return;
+
+ case 23:
+ m_opcode = "ps_sel";
+ m_operands = StringFromFormat("p%u>=0?p%u:p%u", FD, FA, FC);
+ return;
+
+ case 24:
+ m_opcode = "ps_res";
+ m_operands = StringFromFormat("p%u, (1/p%u)", FD, FB);
+ return;
+
+ case 25:
+ m_opcode = "ps_mul";
+ m_operands = StringFromFormat("p%u, p%u*p%u", FD, FA, FC);
+ return;
+
+ case 26: // rsqrte
+ m_opcode = "ps_rsqrte";
+ m_operands = StringFromFormat("p%u, p%u", FD, FB);
+ return;
+
+ case 28: // msub
+ m_opcode = "ps_msub";
+ m_operands = StringFromFormat("p%u, p%u*p%u-p%u", FD, FA, FC, FB);
+ return;
+
+ case 29: // madd
+ m_opcode = "ps_madd";
+ m_operands = StringFromFormat("p%u, p%u*p%u+p%u", FD, FA, FC, FB);
+ return;
+
+ case 30: // nmsub
+ m_opcode = "ps_nmsub";
+ m_operands = StringFromFormat("p%u, -(p%u*p%u-p%u)", FD, FA, FC, FB);
+ return;
+
+ case 31: // nmadd
+ m_opcode = "ps_nmadd";
+ m_operands = StringFromFormat("p%u, -(p%u*p%u+p%u)", FD, FA, FC, FB);
+ return;
+
+ case 10:
+ m_opcode = "ps_sum0";
+ m_operands = StringFromFormat("p%u, 0=p%u+p%u, 1=p%u", FD, FA, FB, FC);
+ return;
+
+ case 11:
+ m_opcode = "ps_sum1";
+ m_operands = StringFromFormat("p%u, 0=p%u, 1=p%u+p%u", FD, FC, FA, FB);
+ return;
+
+ case 12:
+ m_opcode = "ps_muls0";
+ m_operands = StringFromFormat("p%u, p%u*p%u[0]", FD, FA, FC);
+ return;
+
+ case 13:
+ m_opcode = "ps_muls1";
+ m_operands = StringFromFormat("p%u, p%u*p%u[1]", FD, FA, FC);
+ return;
+
+ case 14:
+ m_opcode = "ps_madds0";
+ m_operands = StringFromFormat("p%u, p%u*p%u[0]+p%u", FD, FA, FC, FB);
+ return;
+
+ case 15:
+ m_opcode = "ps_madds1";
+ m_operands = StringFromFormat("p%u, p%u*p%u[1]+p%u", FD, FA, FC, FB);
+ return;
+ }
+
+ switch ((inst >> 1) & 0x3FF)
+ {
+ // 10-bit suckers (?)
+ case 40: // nmadd
+ m_opcode = "ps_neg";
+ m_operands = StringFromFormat("p%u, -p%u", FD, FB);
+ return;
+
+ case 72: // nmadd
+ m_opcode = "ps_mr";
+ m_operands = StringFromFormat("p%u, p%u", FD, FB);
+ return;
+
+ case 136:
+ m_opcode = "ps_nabs";
+ m_operands = StringFromFormat("p%u, -|p%u|", FD, FB);
+ return;
+
+ case 264:
+ m_opcode = "ps_abs";
+ m_operands = StringFromFormat("p%u, |p%u|", FD, FB);
+ return;
+
+ case 0:
+ m_opcode = "ps_cmpu0";
+ m_operands = "ps_cmpu0";
+ return;
+
+ case 32:
+ m_opcode = "ps_cmpq0";
+ m_operands = "ps_cmpo0";
+ return;
+
+ case 64:
+ m_opcode = "ps_cmpu1";
+ m_operands = "ps_cmpu1";
+ return;
+
+ case 96:
+ m_opcode = "ps_cmpo1";
+ m_operands = "ps_cmpo1";
+ return;
+
+ case 528:
+ m_opcode = "ps_merge00";
+ m_operands = StringFromFormat("p%u, p%u[0],p%u[0]", FD, FA, FB);
+ return;
+
+ case 560:
+ m_opcode = "ps_merge01";
+ m_operands = StringFromFormat("p%u, p%u[0],p%u[1]", FD, FA, FB);
+ return;
+
+ case 592:
+ m_opcode = "ps_merge10";
+ m_operands = StringFromFormat("p%u, p%u[1],p%u[0]", FD, FA, FB);
+ return;
+
+ case 624:
+ m_opcode = "ps_merge11";
+ m_operands = StringFromFormat("p%u, p%u[1],p%u[1]", FD, FA, FB);
+ return;
+
+ case 1014:
+ m_opcode = "dcbz_l";
+ m_operands = "";
+ return;
+ }
+
+ // default:
+ m_opcode = StringFromFormat("ps_%i", ((inst >> 1) & 0x1f));
+ m_operands = "---";
+}
+
+void GekkoDisassembler::ps_mem(u32 inst)
+{
+ switch (PPCGETIDX(inst))
+ {
+ case 56:
+ m_opcode = "psq_l";
+ m_operands = StringFromFormat("p%u, %i(r%u)", RS, SEX12(inst & 0xFFF), RA);
+ break;
+
+ case 57:
+ m_opcode = "psq_lu";
+ m_operands = "";
+ break;
+
+ case 60:
+ m_opcode = "psq_st";
+ m_operands = StringFromFormat("%i(r%u), p%u", SEX12(inst & 0xFFF), RA, RS);
+ break;
+
+ case 61:
+ m_opcode = "psq_stu";
+ m_operands = StringFromFormat("r%u, p%u ?", RA, RS);
+ break;
+ }
+}
+
+// Disassemble PPC instruction and return a pointer to the next
+// instruction, or nullptr if an error occured.
+u32* GekkoDisassembler::DoDisassembly(bool big_endian)
+{
+ u32 in = *m_instr;
+
+ if (!big_endian)
+ {
+ in = (in & 0xff) << 24 | (in & 0xff00) << 8 | (in & 0xff0000) >> 8 |
+ (in & 0xff000000) >> 24;
+ }
+
+ m_opcode.clear();
+ m_operands.clear();
+ m_type = PPCINSTR_OTHER;
+ m_flags = 0;
+
+ switch (PPCGETIDX(in))
+ {
+ case 0:
+ {
+ int block = in & 0x3FFFFFF;
+ if (block)
+ {
+ m_opcode = "JITblock";
+ m_operands = StringFromFormat("%i", block);
+ }
+ else
+ {
+ m_opcode = "";
+ m_operands = "---";
+ }
+ }
+ break;
+
+ case 1: // HLE call
+ m_opcode = "HLE";
+ break;
+
+ case 2:
+ trapi(in, PPCF_64); // tdi
+ break;
+
+ case 3:
+ trapi(in, 0); // twi
+ break;
+
+ case 4:
+ ps(in);
+ break;
+
+ case 56:
+ case 57:
+ case 60:
+ case 61:
+ ps_mem(in);
+ break;
+
+ case 7:
+ m_opcode = "mulli";
+ m_operands = imm(in, 0, 0, false);
+ break;
+
+ case 8:
+ m_opcode = "subfic";
+ m_operands = imm(in, 0, 0, false);
+ break;
+
+ case 10:
+ cmpi(in, 1); // cmpli
+ break;
+
+ case 11:
+ cmpi(in, 0); // cmpi
+ break;
+
+ case 12:
+ addi(in, "ic"); // addic
+ break;
+
+ case 13:
+ addi(in, "ic."); // addic.
+ break;
+
+ case 14:
+ addi(in, "i"); // addi
+ break;
+
+ case 15:
+ addi(in, "is"); // addis
+ break;
+
+ case 16:
+ bc(in);
+ break;
+
+ case 17:
+ if ((in & ~PPCIDXMASK) == 2)
+ m_opcode = "sc";
+ else
+ ill(in);
+ break;
+
+ case 18:
+ bli(in);
+ break;
+
+ case 19:
+ switch (PPCGETIDX2(in))
+ {
+ case 0:
+ mcrf(in, '\0'); // mcrf
+ break;
+
+ case 16:
+ branch(in, "lr", 0, 0); // bclr
+ break;
+
+ case 33:
+ crop(in, "nor", "not"); // crnor
+ break;
+
+ case 50:
+ nooper(in, "rfi", PPCF_SUPER);
+ break;
+
+ case 129:
+ crop(in, "andc", nullptr); // crandc
+ break;
+
+ case 150:
+ nooper(in, "isync", 0);
+ break;
+
+ case 193:
+ crop(in, "xor", "clr"); // crxor
+ break;
+
+ case 225:
+ crop(in, "nand", nullptr); // crnand
+ break;
+
+ case 257:
+ crop(in, "and", nullptr); // crand
+ break;
+
+ case 289:
+ crop(in, "eqv", "set"); // creqv
+ break;
+
+ case 417:
+ crop(in, "orc", nullptr); // crorc
+ break;
+
+ case 449:
+ crop(in, "or", "move"); // cror
+ break;
+
+ case 528:
+ branch(in, "ctr", 0, 0); // bcctr
+ break;
+
+ default:
+ ill(in);
+ break;
+ }
+ break;
+
+ case 20:
+ rlw(in, "imi", 0); // rlwimi
+ break;
+
+ case 21:
+ rlw(in, "inm", 0); // rlwinm
+ break;
+
+ case 23:
+ rlw(in, "nm", 1); // rlwnm
+ break;
+
+ case 24:
+ if (in & ~PPCIDXMASK)
+ ori(in, "ori");
+ else
+ m_opcode = "nop";
+ break;
+
+ case 25:
+ ori(in, "oris");
+ break;
+
+ case 26:
+ ori(in, "xori");
+ break;
+
+ case 27:
+ ori(in, "xoris");
+ break;
+
+ case 28:
+ ori(in, "andi.");
+ break;
+
+ case 29:
+ ori(in, "andis.");
+ break;
+
+ case 30:
+ switch (in & 0x1c)
+ {
+ case 0:
+ rld(in, "icl", 0); // rldicl
+ break;
+ case 1:
+ rld(in, "icr", 0); // rldicr
+ break;
+ case 2:
+ rld(in, "ic", 0); // rldic
+ break;
+ case 3:
+ rld(in, "imi", 0); // rldimi
+ break;
+ case 4:
+ rld(in, in & 2 ? "cl" : "cr", 1); // rldcl, rldcr
+ break;
+ default:
+ ill(in);
+ break;
+ }
+ break;
+
+ case 31:
+ switch (PPCGETIDX2(in))
+ {
+ case 0:
+ case 32:
+ if (in & 1)
+ ill(in);
+ else
+ cmp(in); // cmp, cmpl
+ break;
+
+ case 4:
+ if (in & 1)
+ ill(in);
+ else
+ trap(in, 0); // tw
+ break;
+
+ case 8:
+ case (PPCOE >> 1) + 8:
+ dab(swapab(in), "subc", 7, 0, 1, -1, 0);
+ break;
+
+ case 9:
+ dab(in, "mulhdu", 7, 0, 0, -1, PPCF_64);
+ break;
+
+ case 10:
+ case (PPCOE >> 1) + 10:
+ dab(in, "addc", 7, 0, 1, -1, 0);
+ break;
+
+ case 11:
+ dab(in, "mulhwu", 7, 0, 0, -1, 0);
+ break;
+
+ case 19:
+ if (in & (PPCAMASK | PPCBMASK))
+ ill(in);
+ else
+ dab(in, "mfcr", 4, 0, 0, 0, 0);
+ break;
+
+ case 20:
+ dab(in, "lwarx", 7, 0, 0, 0, 0);
+ break;
+
+ case 21:
+ dab(in, "ldx", 7, 0, 0, 0, PPCF_64);
+ break;
+
+ case 23:
+ dab(in, "lwzx", 7, 0, 0, 0, 0);
+ break;
+
+ case 24:
+ dab(in, "slw", 7, 1, 0, -1, 0);
+ break;
+
+ case 26:
+ if (in & PPCBMASK)
+ ill(in);
+ else
+ dab(in, "cntlzw", 6, 1, 0, -1, 0);
+ break;
+
+ case 27:
+ dab(in, "sld", 7, 1, 0, -1, PPCF_64);
+ break;
+
+ case 28:
+ dab(in, "and", 7, 1, 0, -1, 0);
+ break;
+
+ case 40:
+ case (PPCOE >> 1) + 40:
+ dab(swapab(in), "sub", 7, 0, 1, -1, 0);
+ break;
+
+ case 53:
+ dab(in, "ldux", 7, 0, 0, 0, PPCF_64);
+ break;
+
+ case 54:
+ if (in & PPCDMASK)
+ ill(in);
+ else
+ dab(in, "dcbst", 3, 0, 0, 0, 0);
+ break;
+
+ case 55:
+ dab(in, "lwzux", 7, 0, 0, 0, 0);
+ break;
+
+ case 58:
+ if (in & PPCBMASK)
+ ill(in);
+ else
+ dab(in, "cntlzd", 6, 1, 0, -1, PPCF_64);
+ break;
+
+ case 60:
+ dab(in, "andc", 7, 1, 0, -1, 0);
+ break;
+
+ case 68:
+ trap(in, PPCF_64); // td
+ break;
+
+ case 73:
+ dab(in, "mulhd", 7, 0, 0, -1, PPCF_64);
+ break;
+
+ case 75:
+ dab(in, "mulhw", 7, 0, 0, -1, 0);
+ break;
+
+ case 83:
+ if (in & (PPCAMASK | PPCBMASK))
+ ill(in);
+ else
+ dab(in, "mfmsr", 4, 0, 0, 0, PPCF_SUPER);
+ break;
+
+ case 84:
+ dab(in, "ldarx", 7, 0, 0, 0, PPCF_64);
+ break;
+
+ case 86:
+ if (in & PPCDMASK)
+ ill(in);
+ else
+ dab(in, "dcbf", 3, 0, 0, 0, 0);
+ break;
+
+ case 87:
+ dab(in, "lbzx", 7, 0, 0, 0, 0);
+ break;
+
+ case 104:
+ case (PPCOE >> 1) + 104:
+ if (in & PPCBMASK)
+ ill(in);
+ else
+ dab(in, "neg", 6, 0, 1, -1, 0);
+ break;
+
+ case 119:
+ dab(in, "lbzux", 7, 0, 0, 0, 0);
+ break;
+
+ case 124:
+ if (PPCGETD(in) == PPCGETB(in))
+ dab(in, "not", 6, 1, 0, -1, 0);
+ else
+ dab(in, "nor", 7, 1, 0, -1, 0);
+ break;
+
+ case 136:
+ case (PPCOE >> 1) + 136:
+ dab(in, "subfe", 7, 0, 1, -1, 0);
+ break;
+
+ case 138:
+ case (PPCOE >> 1) + 138:
+ dab(in, "adde", 7, 0, 1, -1, 0);
+ break;
+
+ case 144:
+ mtcr(in);
+ break;
+
+ case 146:
+ if (in & (PPCAMASK | PPCBMASK))
+ ill(in);
+ else
+ dab(in, "mtmsr", 4, 0, 0, 0, PPCF_SUPER);
+ break;
+
+ case 149:
+ dab(in, "stdx", 7, 0, 0, 0, PPCF_64);
+ break;
+
+ case 150:
+ dab(in, "stwcx.", 7, 0, 0, 1, 0);
+ break;
+
+ case 151:
+ dab(in, "stwx", 7, 0, 0, 0, 0);
+ break;
+
+ case 181:
+ dab(in, "stdux", 7, 0, 0, 0, PPCF_64);
+ break;
+
+ case 183:
+ dab(in, "stwux", 7, 0, 0, 0, 0);
+ break;
+
+ case 200:
+ case (PPCOE >> 1) + 200:
+ if (in & PPCBMASK)
+ ill(in);
+ else
+ dab(in, "subfze", 6, 0, 1, -1, 0);
+ break;
+
+ case 202:
+ case (PPCOE >> 1) + 202:
+ if (in & PPCBMASK)
+ ill(in);
+ else
+ dab(in, "addze", 6, 0, 1, -1, 0);
+ break;
+
+ case 210:
+ msr(in, 1); // mfsr
+ break;
+
+ case 214:
+ dab(in, "stdcx.", 7, 0, 0, 1, PPCF_64);
+ break;
+
+ case 215:
+ dab(in, "stbx", 7, 0, 0, 0, 0);
+ break;
+
+ case 232:
+ case (PPCOE >> 1) + 232:
+ if (in & PPCBMASK)
+ ill(in);
+ else
+ dab(in, "subfme", 6, 0, 1, -1, 0);
+ break;
+
+ case 233:
+ case (PPCOE >> 1) + 233:
+ dab(in, "mulld", 7, 0, 1, -1, PPCF_64);
+ break;
+
+ case 234:
+ case (PPCOE >> 1) + 234:
+ if (in & PPCBMASK)
+ ill(in);
+ else
+ dab(in, "addme", 6, 0, 1, -1, 0);
+ break;
+
+ case 235:
+ case (PPCOE >> 1) + 235:
+ dab(in, "mullw", 7, 0, 1, -1, 0);
+ break;
+
+ case 242:
+ if (in & PPCAMASK)
+ ill(in);
+ else
+ dab(in, "mtsrin", 5, 0, 0, 0, PPCF_SUPER);
+ break;
+
+ case 246:
+ if (in & PPCDMASK)
+ ill(in);
+ else
+ dab(in, "dcbtst", 3, 0, 0, 0, 0);
+ break;
+
+ case 247:
+ dab(in, "stbux", 7, 0, 0, 0, 0);
+ break;
+
+ case 266:
+ case (PPCOE >> 1) + 266:
+ dab(in, "add", 7, 0, 1, -1, 0);
+ break;
+
+ case 278:
+ if (in & PPCDMASK)
+ ill(in);
+ else
+ dab(in, "dcbt", 3, 0, 0, 0, 0);
+ break;
+
+ case 279:
+ dab(in, "lhzx", 7, 0, 0, 0, 0);
+ break;
+
+ case 284:
+ dab(in, "eqv", 7, 1, 0, -1, 0);
+ break;
+
+ case 306:
+ if (in & (PPCDMASK | PPCAMASK))
+ ill(in);
+ else
+ dab(in, "tlbie", 1, 0, 0, 0, PPCF_SUPER);
+ break;
+
+ case 310:
+ dab(in, "eciwx", 7, 0, 0, 0, 0);
+ break;
+
+ case 311:
+ dab(in, "lhzux", 7, 0, 0, 0, 0);
+ break;
+
+ case 316:
+ dab(in, "xor", 7, 1, 0, -1, 0);
+ break;
+
+ case 339:
+ mspr(in, 0); // mfspr
+ break;
+
+ case 341:
+ dab(in, "lwax", 7, 0, 0, 0, PPCF_64);
+ break;
+
+ case 343:
+ dab(in, "lhax", 7, 0, 0, 0, 0);
+ break;
+
+ case 370:
+ nooper(in, "tlbia", PPCF_SUPER);
+ break;
+
+ case 371:
+ mtb(in); // mftb
+ break;
+
+ case 373:
+ dab(in, "lwaux", 7, 0, 0, 0, PPCF_64);
+ break;
+
+ case 375:
+ dab(in, "lhaux", 7, 0, 0, 0, 0);
+ break;
+
+ case 407:
+ dab(in, "sthx", 7, 0, 0, 0, 0);
+ break;
+
+ case 412:
+ dab(in, "orc", 7, 1, 0, -1, 0);
+ break;
+
+ case 413:
+ sradi(in); // sradi
+ break;
+
+ case 434:
+ if (in & (PPCDMASK | PPCAMASK))
+ ill(in);
+ else
+ dab(in, "slbie", 1, 0, 0, 0, PPCF_SUPER | PPCF_64);
+ break;
+
+ case 438:
+ dab(in, "ecowx", 7, 0, 0, 0, 0);
+ break;
+
+ case 439:
+ dab(in, "sthux", 7, 0, 0, 0, 0);
+ break;
+
+ case 444:
+ if (PPCGETD(in) == PPCGETB(in))
+ dab(in, "mr", 6, 1, 0, -1, 0);
+ else
+ dab(in, "or", 7, 1, 0, -1, 0);
+ break;
+
+ case 457:
+ case (PPCOE >> 1) + 457:
+ dab(in, "divdu", 7, 0, 1, -1, PPCF_64);
+ break;
+
+ case 459:
+ case (PPCOE >> 1) + 459:
+ dab(in, "divwu", 7, 0, 1, -1, 0);
+ break;
+
+ case 467:
+ mspr(in, 1); // mtspr
+ break;
+
+ case 470:
+ if (in & PPCDMASK)
+ ill(in);
+ else
+ dab(in, "dcbi", 3, 0, 0, 0, 0);
+ break;
+
+ case 476:
+ dab(in, "nand", 7, 1, 0, -1, 0);
+ break;
+
+ case 489:
+ case (PPCOE >> 1) + 489:
+ dab(in, "divd", 7, 0, 1, -1, PPCF_64);
+ break;
+
+ case 491:
+ case (PPCOE >> 1) + 491:
+ dab(in, "divw", 7, 0, 1, -1, 0);
+ break;
+
+ case 498:
+ nooper(in, "slbia", PPCF_SUPER | PPCF_64);
+ break;
+
+ case 512:
+ if (in & 0x007ff801)
+ {
+ ill(in);
+ }
+ else
+ {
+ m_opcode = "mcrxr";
+ m_operands = StringFromFormat("cr%d", (int)PPCGETCRD(in));
+ }
+ break;
+
+ case 533:
+ dab(in, "lswx", 7, 0, 0, 0, 0);
+ break;
+
+ case 534:
+ dab(in, "lwbrx", 7, 0, 0, 0, 0);
+ break;
+
+ case 535:
+ fdab(in, "lfsx", 7);
+ break;
+
+ case 536:
+ dab(in, "srw", 7, 1, 0, -1, 0);
+ break;
+
+ case 539:
+ dab(in, "srd", 7, 1, 0, -1, PPCF_64);
+ break;
+
+ case 566:
+ nooper(in, "tlbsync", PPCF_SUPER);
+ break;
+
+ case 567:
+ fdab(in, "lfsux", 7);
+ break;
+
+ case 595:
+ msr(in, 0); // mfsr
+ break;
+
+ case 597:
+ rrn(in, "lswi", 0, 0, 0, 0);
+ break;
+
+ case 598:
+ nooper(in, "sync", PPCF_SUPER);
+ break;
+
+ case 599:
+ fdab(in, "lfdx", 7);
+ break;
+
+ case 631:
+ fdab(in, "lfdux", 7);
+ break;
+
+ case 659:
+ if (in & PPCAMASK)
+ ill(in);
+ else
+ dab(in, "mfsrin", 5, 0, 0, 0, PPCF_SUPER);
+ break;
+
+ case 661:
+ dab(in, "stswx", 7, 0, 0, 0, 0);
+ break;
+
+ case 662:
+ dab(in, "stwbrx", 7, 0, 0, 0, 0);
+ break;
+
+ case 663:
+ fdab(in, "stfsx", 7);
+ break;
+
+ case 695:
+ fdab(in, "stfsux", 7);
+ break;
+
+ case 725:
+ rrn(in, "stswi", 0, 0, 0, 0);
+ break;
+
+ case 727:
+ fdab(in, "stfdx", 7);
+ break;
+
+ case 759:
+ fdab(in, "stfdux", 7);
+ break;
+
+ case 790:
+ dab(in, "lhbrx", 7, 0, 0, 0, 0);
+ break;
+
+ case 792:
+ dab(in, "sraw", 7, 1, 0, -1, 0);
+ break;
+
+ case 794:
+ dab(in, "srad", 7, 1, 0, -1, PPCF_64);
+ break;
+
+ case 824:
+ rrn(in, "srawi", 1, 0, -1, 0);
+ break;
+
+ case 854:
+ nooper(in, "eieio", PPCF_SUPER);
+ break;
+
+ case 918:
+ dab(in, "sthbrx", 7, 0, 0, 0, 0);
+ break;
+
+ case 922:
+ if (in & PPCBMASK)
+ ill(in);
+ else
+ dab(in, "extsh", 6, 1, 0, -1, 0);
+ break;
+
+ case 954:
+ if (in & PPCBMASK)
+ ill(in);
+ else
+ dab(in, "extsb", 6, 1, 0, -1, 0);
+ break;
+
+ case 982:
+ if (in & PPCDMASK)
+ ill(in);
+ else
+ dab(in, "icbi", 3, 0, 0, 0, 0);
+ break;
+
+ case 983:
+ fdab(in, "stfiwx", 7);
+ break;
+
+ case 986:
+ if (in & PPCBMASK)
+ ill(in);
+ else
+ dab(in, "extsw", 6, 1, 0, -1, PPCF_64);
+ break;
+
+ case 1014:
+ if (in & PPCDMASK)
+ ill(in);
+ else
+ dab(in, "dcbz", 3, 0, 0, 0, 0);
+ break;
+
+ default:
+ ill(in);
+ break;
+ }
+ break;
+
+ case 32:
+ case 33:
+ case 34:
+ case 35:
+ case 36:
+ case 37:
+ case 38:
+ case 39:
+ case 40:
+ case 41:
+ case 42:
+ case 43:
+ case 44:
+ case 45:
+ case 46:
+ case 47:
+ ldst(in, ldstnames[PPCGETIDX(in) - 32], 'r', 0);
+ break;
+
+ case 48:
+ case 49:
+ case 50:
+ case 51:
+ case 52:
+ case 53:
+ case 54:
+ case 55:
+ ldst(in, ldstnames[PPCGETIDX(in) - 32], 'f', 0);
+ break;
+
+ case 58:
+ switch (in & 3)
+ {
+ case 0:
+ ldst(in&~3, "ld", 'r', PPCF_64);
+ break;
+ case 1:
+ ldst(in&~3, "ldu", 'r', PPCF_64);
+ break;
+ case 2:
+ ldst(in&~3, "lwa", 'r', PPCF_64);
+ break;
+ default:
+ ill(in);
+ break;
+ }
+ break;
+
+ case 59:
+ switch (in & 0x3e)
+ {
+ case 36:
+ fdabc(in, "divs", 5, 0);
+ break;
+
+ case 40:
+ fdabc(in, "subs", 5, 0);
+ break;
+
+ case 42:
+ fdabc(in, "adds", 5, 0);
+ break;
+
+ case 44:
+ fdabc(in, "sqrts", 2, 0);
+ break;
+
+ case 48:
+ fdabc(in, "res", 2, 0);
+ break;
+
+ case 50:
+ fdabc(in, "muls", 6, 0);
+ break;
+
+ case 56:
+ fdabc(in, "msubs", 7, 0);
+ break;
+
+ case 58:
+ fdabc(in, "madds", 7, 0);
+ break;
+
+ case 60:
+ fdabc(in, "nmsubs", 7, 0);
+ break;
+
+ case 62:
+ fdabc(in, "nmadds", 7, 0);
+ break;
+
+ default:
+ ill(in);
+ break;
+ }
+ break;
+
+ case 62:
+ switch (in & 3)
+ {
+ case 0:
+ ldst(in&~3, "std", 'r', PPCF_64);
+ break;
+ case 1:
+ ldst(in&~3, "stdu", 'r', PPCF_64);
+ break;
+ default:
+ ill(in);
+ break;
+ }
+ break;
+
+ case 63:
+ if (in & 32)
+ {
+ switch (in & 0x1e)
+ {
+ case 4:
+ fdabc(in, "div", 5, 0);
+ break;
+
+ case 8:
+ fdabc(in, "sub", 5, 0);
+ break;
+
+ case 10:
+ fdabc(in, "add", 5, 0);
+ break;
+
+ case 12:
+ fdabc(in, "sqrt", 2, 0);
+ break;
+
+ case 14:
+ fdabc(in, "sel", 7, 0);
+ break;
+
+ case 18:
+ fdabc(in, "mul", 6, 0);
+ break;
+
+ case 20:
+ fdabc(in, "rsqrte", 1, 0);
+ break;
+
+ case 24:
+ fdabc(in, "msub", 7, 0);
+ break;
+
+ case 26:
+ fdabc(in, "madd", 7, 0);
+ break;
+
+ case 28:
+ fdabc(in, "nmsub", 7, 0);
+ break;
+
+ case 30:
+ fdabc(in, "nmadd", 7, 0);
+ break;
+
+ case 52:
+ m_opcode = "XXX dp 52";
+ break;
+
+ default:
+ ill(in);
+ break;
+ }
+ }
+ else
+ {
+ switch (PPCGETIDX2(in))
+ {
+ case 0:
+ fcmp(in, 'u');
+ break;
+
+ case 12:
+ fdabc(in, "rsp", 1, 0);
+ break;
+
+ case 14:
+ fdabc(in, "ctiw", 1, 0);
+ break;
+
+ case 15:
+ fdabc(in, "ctiwz", 1, 0);
+ break;
+
+ case 32:
+ fcmp(in, 'o');
+ break;
+
+ case 38:
+ mtfsb(in, 1);
+ break;
+
+ case 40:
+ fdabc(in, "neg", 10, 0);
+ break;
+
+ case 64:
+ mcrf(in, 's'); // mcrfs
+ break;
+
+ case 70:
+ mtfsb(in, 0);
+ break;
+
+ case 72:
+ fmr(in);
+ break;
+
+ case 134:
+ if ((in & 0x006f0800) == 0)
+ {
+ m_opcode = StringFromFormat("mtfsfi%s", rcsel[in & 1]);
+ m_operands = StringFromFormat("cr%d,%d", (int)PPCGETCRD(in), (int)(in & 0xf000) >> 12);
+ }
+ else
+ {
+ ill(in);
+ }
+ break;
+
+ case 136:
+ fdabc(in, "nabs", 10, 0);
+ break;
+
+ case 264:
+ fdabc(in, "abs", 10, 0);
+ break;
+
+ case 583:
+ if (in & (PPCAMASK | PPCBMASK))
+ ill(in);
+ else
+ dab(in, "mffs", 4, 0, 0, -1, 0);
+ break;
+
+ case 711:
+ if ((in & 0x02010000) == 0)
+ {
+ m_opcode = StringFromFormat("mtfsf%s", rcsel[in & 1]);
+ m_operands = StringFromFormat("0x%x,%u", (unsigned int)(in & 0x01fe) >> 17, (int)PPCGETB(in));
+ }
+ else
+ {
+ ill(in);
+ }
+ break;
+
+ case 814:
+ fdabc(in, "fctid", 10, PPCF_64);
+ break;
+
+ case 815:
+ fdabc(in, "fctidz", 10, PPCF_64);
+ break;
+
+ case 846:
+ fdabc(in, "fcfid", 10, PPCF_64);
+ break;
+
+ default:
+ ill(in);
+ break;
+ }
+ }
+ break;
+
+ default:
+ ill(in);
+ break;
+ }
+ return (m_instr + 1);
+}
+
+// simplified interface
+std::string GekkoDisassembler::Disassemble(u32 opcode, u32 current_instruction_address, bool big_endian)
+{
+ u32 opc = opcode;
+ u32 addr = current_instruction_address;
+
+ m_instr = (u32*)&opc;
+ m_iaddr = (u32*)&addr;
+
+ DoDisassembly(big_endian);
+
+ return m_opcode.append("\t").append(m_operands);
+}
+
+static const char* gprnames[] =
+{
+ " r0", " r1", " r2", " r3", " r4", " r5", " r6", " r7",
+ " r8", " r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+ "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
+};
+
+const char* GekkoDisassembler::GetGPRName(u32 index)
+{
+ if (index < 32)
+ return gprnames[index];
+
+ return 0;
+}
+
+static const char* fprnames[] =
+{
+ " f0", " f1", " f2", " f3", " f4", " f5", " f6", " f7",
+ " f8", " f9", "f10", "f11", "f12", "f13", "f14", "f15",
+ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
+ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31"
+};
+
+const char* GekkoDisassembler::GetFPRName(u32 index)
+{
+ if (index < 32)
+ return fprnames[index];
+
+ return 0;
+}
diff --git a/Source/Core/Common/GekkoDisassembler.h b/Source/Core/Common/GekkoDisassembler.h
new file mode 100644
index 0000000000..113c843baa
--- /dev/null
+++ b/Source/Core/Common/GekkoDisassembler.h
@@ -0,0 +1,152 @@
+/* $VER: ppc_disasm.h V1.6 (09.12.2011)
+ *
+ * Disassembler module for the PowerPC microprocessor family
+ * Copyright (c) 1998-2001,2009,2011 Frank Wille
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Modified for use with Dolphin
+
+#pragma once
+
+#include <cstdint>
+#include <string>
+
+#include "Common/CommonTypes.h"
+#include "Common/StringUtil.h"
+
+class GekkoDisassembler final
+{
+public:
+ static std::string Disassemble(u32 opcode, u32 current_instruction_address, bool big_endian = true);
+ static const char* GetGPRName(u32 index);
+ static const char* GetFPRName(u32 index);
+
+private:
+ GekkoDisassembler() = delete;
+
+ static void ill(u32 in);
+ static std::string imm(u32 in, int uimm, int type, bool hex);
+
+ static std::string ra_rb(u32 in);
+ static std::string rd_ra_rb(u32 in, int mask);
+ static std::string fd_ra_rb(u32 in, int mask);
+
+ static void trapi(u32 in, unsigned char dmode);
+ static void cmpi(u32 in, int uimm);
+ static void addi(u32 in, const std::string& ext);
+ static size_t branch(u32 in, const char* bname, int aform, int bdisp);
+ static void bc(u32 in);
+ static void bli(u32 in);
+ static void mcrf(u32 in, char c);
+ static void crop(u32 in, const char* n1, const char* n2);
+ static void nooper(u32 in, const char* name, unsigned char dmode);
+ static void rlw(u32 in, const char* name, int i);
+ static void ori(u32 in, const char* name);
+ static void rld(u32 in, const char* name, int i);
+ static void cmp(u32 in);
+ static void trap(u32 in, unsigned char dmode);
+ static void dab(u32 in, const char* name, int mask, int smode, int chkoe, int chkrc, unsigned char dmode);
+ static void rrn(u32 in, const char* name, int smode, int chkoe, int chkrc, unsigned char dmode);
+ static void mtcr(u32 in);
+ static void msr(u32 in, int smode);
+ static void mspr(u32 in, int smode);
+ static void mtb(u32 in);
+ static void sradi(u32 in);
+ static void ldst(u32 in, const char* name, char reg, unsigned char dmode);
+ static void fdabc(u32 in, const char* name, int mask, unsigned char dmode);
+ static void fmr(u32 in);
+ static void fdab(u32 in, const char* name, int mask);
+ static void fcmp(u32 in, char c);
+ static void mtfsb(u32 in, int n);
+ static void ps(u32 inst);
+ static void ps_mem(u32 inst);
+
+ static u32* DoDisassembly(bool big_endian);
+
+ static u32 HelperRotateMask(int r, int mb, int me)
+ {
+ //first make 001111111111111 part
+ unsigned int begin = 0xFFFFFFFF >> mb;
+ //then make 000000000001111 part, which is used to flip the bits of the first one
+ unsigned int end = me < 31 ? (0xFFFFFFFF >> (me + 1)) : 0;
+ //do the bitflip
+ unsigned int mask = begin ^ end;
+ //and invert if backwards
+ if (me < mb)
+ mask = ~mask;
+ //rotate the mask so it can be applied to source reg
+ //return _rotl(mask, 32 - r);
+ return (mask << (32 - r)) | (mask >> r);
+ }
+
+ static std::string ldst_offs(u32 val)
+ {
+ if (val == 0)
+ {
+ return "0";
+ }
+ else
+ {
+ if (val & 0x8000)
+ {
+ return StringFromFormat("-0x%.4X", ((~val) & 0xffff) + 1);
+ }
+ else
+ {
+ return StringFromFormat("0x%.4X", val);
+ }
+ }
+ }
+
+ static int SEX12(u32 x)
+ {
+ return x & 0x800 ? (x | 0xFFFFF000) : x;
+ }
+
+ enum InstructionType
+ {
+ PPCINSTR_OTHER = 0, // No additional info for other instr.
+ PPCINSTR_BRANCH = 1, // Branch dest. = PC+displacement
+ PPCINSTR_LDST = 2, // Load/store instruction: displ(sreg)
+ PPCINSTR_IMM = 3, // 16-bit immediate val. in displacement
+ };
+
+ enum Flags
+ {
+ PPCF_ILLEGAL = (1 << 0), // Illegal PowerPC instruction
+ PPCF_UNSIGNED = (1 << 1), // Unsigned immediate instruction
+ PPCF_SUPER = (1 << 2), // Supervisor level instruction
+ PPCF_64 = (1 << 3), // 64-bit only instruction
+ };
+
+ static u32* m_instr; // Pointer to instruction to disassemble
+ static u32* m_iaddr; // Instruction.address., usually the same as instr
+ static std::string m_opcode; // Buffer for opcode, min. 10 chars.
+ static std::string m_operands; // Operand buffer, min. 24 chars.
+ static unsigned char m_type; // Type of instruction, see below
+ static unsigned char m_flags; // Additional flags
+ static unsigned short m_sreg; // Register in load/store instructions
+ static u32 m_displacement; // Branch- or load/store displacement
+};
diff --git a/Source/Core/Core/Debugger/PPCDebugInterface.cpp b/Source/Core/Core/Debugger/PPCDebugInterface.cpp
index d07d49c097..ed46e18db3 100644
--- a/Source/Core/Core/Debugger/PPCDebugInterface.cpp
+++ b/Source/Core/Core/Debugger/PPCDebugInterface.cpp
@@ -2,7 +2,9 @@
// Licensed under GPLv2
// Refer to the license.txt file included.
-#include "PowerPCDisasm.h"
+#include <string>
+
+#include "Common/GekkoDisassembler.h"
#include "Core/Core.h"
#include "Core/Host.h"
@@ -15,31 +17,37 @@
#include "Core/PowerPC/PPCSymbolDB.h"
#include "Core/PowerPC/JitCommon/JitBase.h"
-void PPCDebugInterface::Disassemble(unsigned int address, char *dest, int max_size)
+std::string PPCDebugInterface::Disassemble(unsigned int address)
{
// Memory::ReadUnchecked_U32 seemed to crash on shutdown
- if (PowerPC::GetState() == PowerPC::CPU_POWERDOWN) return;
+ if (PowerPC::GetState() == PowerPC::CPU_POWERDOWN)
+ return "";
if (Core::GetState() != Core::CORE_UNINITIALIZED)
{
if (Memory::IsRAMAddress(address, true, true))
{
u32 op = Memory::Read_Instruction(address);
- DisassembleGekko(op, address, dest, max_size);
+ std::string disasm = GekkoDisassembler::Disassemble(op, address);
+
UGeckoInstruction inst;
inst.hex = Memory::ReadUnchecked_U32(address);
- if (inst.OPCD == 1) {
- strcat(dest, " (hle)");
+
+ if (inst.OPCD == 1)
+ {
+ disasm += " (hle)";
}
+
+ return disasm;
}
else
{
- strcpy(dest, "(No RAM here)");
+ return "(No RAM here)";
}
}
else
{
- strcpy(dest, "<unknown>");
+ return "<unknown>";
}
}
diff --git a/Source/Core/Core/Debugger/PPCDebugInterface.h b/Source/Core/Core/Debugger/PPCDebugInterface.h
index ba362694f1..c80416d58b 100644
--- a/Source/Core/Core/Debugger/PPCDebugInterface.h
+++ b/Source/Core/Core/Debugger/PPCDebugInterface.h
@@ -14,7 +14,7 @@ class PPCDebugInterface final : public DebugInterface
{
public:
PPCDebugInterface(){}
- virtual void Disassemble(unsigned int address, char *dest, int max_size) override;
+ virtual std::string Disassemble(unsigned int address) override;
virtual void GetRawMemoryString(int memory, unsigned int address, char *dest, int max_size) override;
virtual int GetInstructionSize(int /*instruction*/) override {return 4;}
virtual bool IsAlive() override;
diff --git a/Source/Core/Core/HW/DSPLLE/DSPDebugInterface.cpp b/Source/Core/Core/HW/DSPLLE/DSPDebugInterface.cpp
index 4520ddf80a..3ccd46a589 100644
--- a/Source/Core/Core/HW/DSPLLE/DSPDebugInterface.cpp
+++ b/Source/Core/Core/HW/DSPLLE/DSPDebugInterface.cpp
@@ -2,17 +2,18 @@
// Licensed under GPLv2
// Refer to the license.txt file included.
+#include <string>
+
#include "Core/DSP/DSPCore.h"
#include "Core/DSP/DSPDisassembler.h"
#include "Core/DSP/DSPMemoryMap.h"
#include "Core/HW/DSPLLE/DSPDebugInterface.h"
#include "Core/HW/DSPLLE/DSPSymbols.h"
-void DSPDebugInterface::Disassemble(unsigned int address, char *dest, int max_size)
+std::string DSPDebugInterface::Disassemble(unsigned int address)
{
// we'll treat addresses as line numbers.
- strncpy(dest, DSPSymbols::GetLineText(address), max_size);
- dest[max_size-1] = 0;
+ return DSPSymbols::GetLineText(address);
}
void DSPDebugInterface::GetRawMemoryString(int memory, unsigned int address, char *dest, int max_size)
diff --git a/Source/Core/Core/HW/DSPLLE/DSPDebugInterface.h b/Source/Core/Core/HW/DSPLLE/DSPDebugInterface.h
index f4a2494481..2342b940f0 100644
--- a/Source/Core/Core/HW/DSPLLE/DSPDebugInterface.h
+++ b/Source/Core/Core/HW/DSPLLE/DSPDebugInterface.h
@@ -5,7 +5,6 @@
#pragma once
#include <string>
-#include <string.h>
#include "Common/Common.h"
#include "Common/DebugInterface.h"
@@ -14,7 +13,7 @@ class DSPDebugInterface final : public DebugInterface
{
public:
DSPDebugInterface(){}
- virtual void Disassemble(unsigned int address, char *dest, int max_size) override;
+ virtual std::string Disassemble(unsigned int address) override;
virtual void GetRawMemoryString(int memory, unsigned int address, char *dest, int max_size) override;
virtual int GetInstructionSize(int instruction) override { return 1; }
virtual bool IsAlive() override;
diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp
index ff3bd8c4f8..070c369394 100644
--- a/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp
+++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp
@@ -5,8 +5,7 @@
#include <cinttypes>
#include <string>
-#include "PowerPCDisasm.h"
-
+#include "Common/GekkoDisassembler.h"
#include "Common/StringUtil.h"
#include "Core/Host.h"
#include "Core/Debugger/Debugger_SymbolMap.h"
@@ -82,10 +81,8 @@ static void Trace(UGeckoInstruction& instCode)
fregs += StringFromFormat("f%02d: %08" PRIx64 " %08" PRIx64 " ", i, PowerPC::ppcState.ps[i][0], PowerPC::ppcState.ps[i][1]);
}
- char ppcInst[256];
- DisassembleGekko(instCode.hex, PC, ppcInst, 256);
-
- DEBUG_LOG(POWERPC, "INTER PC: %08x SRR0: %08x SRR1: %08x CRval: %016lx FPSCR: %08x MSR: %08x LR: %08x %s %08x %s", PC, SRR0, SRR1, PowerPC::ppcState.cr_val[0], PowerPC::ppcState.fpscr, PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs.c_str(), instCode.hex, ppcInst);
+ std::string ppc_inst = GekkoDisassembler::Disassemble(instCode.hex, PC);
+ DEBUG_LOG(POWERPC, "INTER PC: %08x SRR0: %08x SRR1: %08x CRval: %016lx FPSCR: %08x MSR: %08x LR: %08x %s %08x %s", PC, SRR0, SRR1, PowerPC::ppcState.cr_val[0], PowerPC::ppcState.fpscr, PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs.c_str(), instCode.hex, ppc_inst.c_str());
}
int Interpreter::SingleStepInner(void)
@@ -312,9 +309,8 @@ void Interpreter::unknown_instruction(UGeckoInstruction _inst)
{
if (_inst.hex != 0)
{
- char disasm[256];
- DisassembleGekko(Memory::ReadUnchecked_U32(last_pc), last_pc, disasm, 256);
- NOTICE_LOG(POWERPC, "Last PC = %08x : %s", last_pc, disasm);
+ std::string disasm = GekkoDisassembler::Disassemble(Memory::ReadUnchecked_U32(last_pc), last_pc);
+ NOTICE_LOG(POWERPC, "Last PC = %08x : %s", last_pc, disasm.c_str());
Dolphin_Debugger::PrintCallstack();
_dbg_assert_msg_(POWERPC, 0, "\nIntCPU: Unknown instruction %08x at PC = %08x last_PC = %08x LR = %08x\n", _inst.hex, PC, last_pc, LR);
}
diff --git a/Source/Core/Core/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/PowerPC/Jit64/Jit.cpp
index 405d183a80..11a6e39b0c 100644
--- a/Source/Core/Core/PowerPC/Jit64/Jit.cpp
+++ b/Source/Core/Core/PowerPC/Jit64/Jit.cpp
@@ -21,7 +21,7 @@
#include "Core/PowerPC/Jit64/JitAsm.h"
#include "Core/PowerPC/Jit64/JitRegCache.h"
#if defined(_DEBUG) || defined(DEBUGFAST)
-#include "PowerPCDisasm.h"
+#include "Common/GekkoDisassembler.h"
#endif
using namespace Gen;
@@ -613,9 +613,8 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
#if defined(_DEBUG) || defined(DEBUGFAST)
if (gpr.SanityCheck() || fpr.SanityCheck())
{
- char ppcInst[256];
- DisassembleGekko(ops[i].inst.hex, em_address, ppcInst, 256);
- //NOTICE_LOG(DYNA_REC, "Unflushed register: %s", ppcInst);
+ std::string ppc_inst = GekkoDisassembler::Disassemble(ops[i].inst.hex, em_address);
+ //NOTICE_LOG(DYNA_REC, "Unflushed register: %s", ppc_inst.c_str());
}
#endif
if (js.skipnext) {
diff --git a/Source/Core/Core/PowerPC/JitCommon/JitBase.cpp b/Source/Core/Core/PowerPC/JitCommon/JitBase.cpp
index 440d507ace..097895ef85 100644
--- a/Source/Core/Core/PowerPC/JitCommon/JitBase.cpp
+++ b/Source/Core/Core/PowerPC/JitCommon/JitBase.cpp
@@ -6,8 +6,8 @@
#include <string>
#include "disasm.h"
-#include "PowerPCDisasm.h"
+#include "Common/GekkoDisassembler.h"
#include "Common/StringUtil.h"
#include "Core/PowerPC/JitCommon/JitBase.h"
@@ -29,15 +29,11 @@ u32 Helper_Mask(u8 mb, u8 me)
void LogGeneratedX86(int size, PPCAnalyst::CodeBuffer *code_buffer, const u8 *normalEntry, JitBlock *b)
{
- std::string ppcdisasm;
-
for (int i = 0; i < size; i++)
{
- char temp[256] = "";
const PPCAnalyst::CodeOp &op = code_buffer->codebuffer[i];
- DisassembleGekko(op.inst.hex, op.address, temp, 256);
- ppcdisasm += StringFromFormat("%08x %s", op.address, temp);
- DEBUG_LOG(DYNA_REC, "IR_X86 PPC: %s\n", ppcdisasm.c_str());
+ std::string temp = StringFromFormat("%08x %s", op.address, GekkoDisassembler::Disassemble(op.inst.hex, op.address).c_str());
+ DEBUG_LOG(DYNA_REC, "IR_X86 PPC: %s\n", temp.c_str());
}
disassembler x64disasm;
diff --git a/Source/Core/Core/PowerPC/PPCSymbolDB.cpp b/Source/Core/Core/PowerPC/PPCSymbolDB.cpp
index 982b246f83..a63c586d97 100644
--- a/Source/Core/Core/PowerPC/PPCSymbolDB.cpp
+++ b/Source/Core/Core/PowerPC/PPCSymbolDB.cpp
@@ -334,9 +334,9 @@ bool PPCSymbolDB::SaveMap(const std::string& filename, bool WithCodes) const
for (int i = 0; i < space; i += 4)
{
int Address = LastAddress + i;
- char disasm[256];
- debugger->Disassemble(Address, disasm, 256);
- fprintf(f.GetHandle(),"%08x %i %20s %s\n", Address, 0, TempSym.c_str(), disasm);
+
+ std::string disasm = debugger->Disassemble(Address);
+ fprintf(f.GetHandle(),"%08x %i %20s %s\n", Address, 0, TempSym.c_str(), disasm.c_str());
}
// Write a blank line after each block
fprintf(f.GetHandle(), "\n");
diff --git a/Source/Core/DolphinWX/Debugger/CodeView.cpp b/Source/Core/DolphinWX/Debugger/CodeView.cpp
index 9d7b869518..7b18a5e9d8 100644
--- a/Source/Core/DolphinWX/Debugger/CodeView.cpp
+++ b/Source/Core/DolphinWX/Debugger/CodeView.cpp
@@ -2,6 +2,7 @@
// Licensed under GPLv2
// Refer to the license.txt file included.
+#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
@@ -189,15 +190,15 @@ void CCodeView::OnMouseUpL(wxMouseEvent& event)
u32 CCodeView::AddrToBranch(u32 addr)
{
- char disasm[256];
- m_debugger->Disassemble(addr, disasm, 256);
- const char *mojs = strstr(disasm, "->0x");
- if (mojs)
+ std::string disasm = m_debugger->Disassemble(addr);
+ size_t pos = disasm.find("->0x");
+
+ if (pos != std::string::npos)
{
- u32 dest;
- sscanf(mojs+4,"%08x", &dest);
- return dest;
+ std::string hex = disasm.substr(pos + 2);
+ return std::stoul(hex, nullptr, 16);
}
+
return 0;
}
@@ -253,16 +254,14 @@ void CCodeView::OnPopupMenu(wxCommandEvent& event)
case IDM_COPYCODE:
{
- char disasm[256];
- m_debugger->Disassemble(m_selection, disasm, 256);
+ std::string disasm = m_debugger->Disassemble(m_selection);
wxTheClipboard->SetData(new wxTextDataObject(StrToWxStr(disasm)));
}
break;
case IDM_COPYHEX:
{
- char temp[24];
- sprintf(temp, "%08x", m_debugger->ReadInstruction(m_selection));
+ std::string temp = StringFromFormat("%08x", m_debugger->ReadInstruction(m_selection));
wxTheClipboard->SetData(new wxTextDataObject(StrToWxStr(temp)));
}
break;
@@ -280,9 +279,8 @@ void CCodeView::OnPopupMenu(wxCommandEvent& event)
u32 end = start + symbol->size;
for (u32 addr = start; addr != end; addr += 4)
{
- char disasm[256];
- m_debugger->Disassemble(addr, disasm, 256);
- text = text + StringFromFormat("%08x: ", addr) + disasm + "\r\n";
+ std::string disasm = m_debugger->Disassemble(addr);
+ text += StringFromFormat("%08x: ", addr) + disasm + "\r\n";
}
wxTheClipboard->SetData(new wxTextDataObject(StrToWxStr(text)));
}
@@ -478,65 +476,51 @@ void CCodeView::OnPaint(wxPaintEvent& event)
// If running
if (m_debugger->IsAlive())
{
- char dis[256];
- m_debugger->Disassemble(address, dis, 256);
- char* dis2 = strchr(dis, '\t');
- char desc[256] = "";
+ std::vector<std::string> dis;
+ SplitString(m_debugger->Disassemble(address), '\t', dis);
+
+ static const size_t VALID_BRANCH_LENGTH = 10;
+ const std::string& opcode = dis[0];
+ const std::string& operands = dis[1];
+ std::string desc;
+
+ // look for hex strings to decode branches
+ std::string hex_str;
+ size_t pos = operands.find("0x8");
+ if (pos != std::string::npos)
+ {
+ hex_str = operands.substr(pos);
+ }
- // If we have a code
- if (dis2)
+ if (hex_str.length() == VALID_BRANCH_LENGTH)
{
- *dis2 = 0;
- dis2++;
- // look for hex strings to decode branches
- const char* mojs = strstr(dis2, "0x8");
- if (mojs)
- {
- for (int k = 0; k < 8; k++)
- {
- bool found = false;
- for (int j = 0; j < 22; j++)
- {
- if (mojs[k + 2] == "0123456789ABCDEFabcdef"[j])
- found = true;
- }
- if (!found)
- {
- mojs = nullptr;
- break;
- }
- }
- }
- if (mojs)
- {
- int offs;
- sscanf(mojs + 2, "%08x", &offs);
- branches[numBranches].src = rowY1 + m_rowHeight / 2;
- branches[numBranches].srcAddr = address / m_align;
- branches[numBranches++].dst = (int)(rowY1 + ((s64)(u32)offs - (s64)(u32)address) * m_rowHeight / m_align + m_rowHeight / 2);
- sprintf(desc, "-->%s", m_debugger->GetDescription(offs).c_str());
- dc.SetTextForeground(wxTheColourDatabase->Find("PURPLE")); // the -> arrow illustrations are purple
- }
- else
- {
- dc.SetTextForeground(*wxBLACK);
- }
+ u32 offs = std::stoul(hex_str, nullptr, 16);
- dc.DrawText(StrToWxStr(dis2), 17 + 17*charWidth, rowY1);
- // ------------
+ branches[numBranches].src = rowY1 + m_rowHeight / 2;
+ branches[numBranches].srcAddr = address / m_align;
+ branches[numBranches++].dst = (int)(rowY1 + ((s64)(u32)offs - (s64)(u32)address) * m_rowHeight / m_align + m_rowHeight / 2);
+ desc = StringFromFormat("-->%s", m_debugger->GetDescription(offs).c_str());
+ dc.SetTextForeground(wxTheColourDatabase->Find("PURPLE")); // the -> arrow illustrations are purple
}
+ else
+ {
+ dc.SetTextForeground(*wxBLACK);
+ }
+
+ dc.DrawText(StrToWxStr(operands), 17 + 17*charWidth, rowY1);
+ // ------------
// Show blr as its' own color
- if (strcmp(dis, "blr"))
+ if (opcode == "blr")
dc.SetTextForeground(wxTheColourDatabase->Find("DARK GREEN"));
else
dc.SetTextForeground(wxTheColourDatabase->Find("VIOLET"));
- dc.DrawText(StrToWxStr(dis), 17 + (m_plain ? 1*charWidth : 9*charWidth), rowY1);
+ dc.DrawText(StrToWxStr(opcode), 17 + (m_plain ? 1*charWidth : 9*charWidth), rowY1);
- if (desc[0] == 0)
+ if (desc.empty())
{
- strcpy(desc, m_debugger->GetDescription(address).c_str());
+ desc = m_debugger->GetDescription(address);
}
if (!m_plain)
@@ -545,7 +529,7 @@ void CCodeView::OnPaint(wxPaintEvent& event)
//char temp[256];
//UnDecorateSymbolName(desc,temp,255,UNDNAME_COMPLETE);
- if (strlen(desc))
+ if (!desc.empty())
{
dc.DrawText(StrToWxStr(desc), 17 + 35 * charWidth, rowY1);
}
diff --git a/Source/Core/DolphinWX/Debugger/JitWindow.cpp b/Source/Core/DolphinWX/Debugger/JitWindow.cpp
index dc10d4ac5c..0ef374ddbe 100644
--- a/Source/Core/DolphinWX/Debugger/JitWindow.cpp
+++ b/Source/Core/DolphinWX/Debugger/JitWindow.cpp
@@ -5,7 +5,6 @@
#include <cstdio>
#include <cstring>
#include <disasm.h> // Bochs
-#include <PowerPCDisasm.h> // Bochs
#include <wx/button.h>
#include <wx/chartype.h>
#include <wx/defs.h>
@@ -22,6 +21,7 @@
#include <wx/windowid.h>
#include "Common/Common.h"
+#include "Common/GekkoDisassembler.h"
#include "Common/StringUtil.h"
#include "Core/PowerPC/Gekko.h"
#include "Core/PowerPC/PPCAnalyst.h"
@@ -161,9 +161,8 @@ void CJitWindow::Compare(u32 em_address)
for (u32 i = 0; i < code_block.m_num_instructions; i++)
{
const PPCAnalyst::CodeOp &op = code_buffer.codebuffer[i];
- char temp[256];
- DisassembleGekko(op.inst.hex, op.address, temp, 256);
- sptr += sprintf(sptr, "%08x %s\n", op.address, temp);
+ std::string temp = GekkoDisassembler::Disassemble(op.inst.hex, op.address);
+ sptr += sprintf(sptr, "%08x %s\n", op.address, temp.c_str());
}
// Add stats to the end of the ppc box since it's generally the shortest.
diff --git a/Source/Core/DolphinWX/Debugger/RegisterView.cpp b/Source/Core/DolphinWX/Debugger/RegisterView.cpp
index a2338d5bd7..25635db528 100644
--- a/Source/Core/DolphinWX/Debugger/RegisterView.cpp
+++ b/Source/Core/DolphinWX/Debugger/RegisterView.cpp
@@ -10,6 +10,7 @@
#include <wx/windowid.h>
#include "Common/CommonTypes.h"
+#include "Common/GekkoDisassembler.h"
#include "Common/StringUtil.h"
#include "Core/HW/ProcessorInterface.h"
#include "Core/PowerPC/Gekko.h"
@@ -22,9 +23,6 @@ class wxWindow;
// F-zero 80005e60 wtf??
-extern const char* GetGPRName(unsigned int index);
-extern const char* GetFPRName(unsigned int index);
-
static const char *special_reg_names[] = {
"PC", "LR", "CTR", "CR", "FPSCR", "MSR", "SRR0", "SRR1", "Exceptions", "Int Mask", "Int Cause",
};
@@ -54,9 +52,9 @@ wxString CRegTable::GetValue(int row, int col)
{
switch (col)
{
- case 0: return StrToWxStr(GetGPRName(row));
+ case 0: return StrToWxStr(GekkoDisassembler::GetGPRName(row));
case 1: return wxString::Format("%08x", GPR(row));
- case 2: return StrToWxStr(GetFPRName(row));
+ case 2: return StrToWxStr(GekkoDisassembler::GetFPRName(row));
case 3: return wxString::Format("%016llx", riPS0(row));
case 4: return wxString::Format("%016llx", riPS1(row));
default: return wxEmptyString;