summaryrefslogtreecommitdiff
path: root/Source/Core/Common
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/Common
parent05a9f5b07abfbb41954b977652e7d11000ea9fae (diff)
parent0718937237db22d26e1b764b4733645c2b9f1562 (diff)
Merge pull request #647 from lioncash/disasm
Common: Introduce the new Gekko disassembler to Common.
Diffstat (limited to 'Source/Core/Common')
-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
6 files changed, 2458 insertions, 2 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
+};