diff options
| author | Pierre Bourdon <delroth@gmail.com> | 2014-08-03 21:52:08 -0700 |
|---|---|---|
| committer | Pierre Bourdon <delroth@gmail.com> | 2014-08-03 21:52:08 -0700 |
| commit | 6befa34b609797b4c48dd45b0f0a7adeba8d8a40 (patch) | |
| tree | 869ff351cb9a9b4115518da6be8837b9846d9e67 /Source/Core | |
| parent | 05a9f5b07abfbb41954b977652e7d11000ea9fae (diff) | |
| parent | 0718937237db22d26e1b764b4733645c2b9f1562 (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.txt | 1 | ||||
| -rw-r--r-- | Source/Core/Common/Common.vcxproj | 4 | ||||
| -rw-r--r-- | Source/Core/Common/Common.vcxproj.filters | 2 | ||||
| -rw-r--r-- | Source/Core/Common/DebugInterface.h | 2 | ||||
| -rw-r--r-- | Source/Core/Common/GekkoDisassembler.cpp | 2299 | ||||
| -rw-r--r-- | Source/Core/Common/GekkoDisassembler.h | 152 | ||||
| -rw-r--r-- | Source/Core/Core/Debugger/PPCDebugInterface.cpp | 24 | ||||
| -rw-r--r-- | Source/Core/Core/Debugger/PPCDebugInterface.h | 2 | ||||
| -rw-r--r-- | Source/Core/Core/HW/DSPLLE/DSPDebugInterface.cpp | 7 | ||||
| -rw-r--r-- | Source/Core/Core/HW/DSPLLE/DSPDebugInterface.h | 3 | ||||
| -rw-r--r-- | Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp | 14 | ||||
| -rw-r--r-- | Source/Core/Core/PowerPC/Jit64/Jit.cpp | 7 | ||||
| -rw-r--r-- | Source/Core/Core/PowerPC/JitCommon/JitBase.cpp | 10 | ||||
| -rw-r--r-- | Source/Core/Core/PowerPC/PPCSymbolDB.cpp | 6 | ||||
| -rw-r--r-- | Source/Core/DolphinWX/Debugger/CodeView.cpp | 108 | ||||
| -rw-r--r-- | Source/Core/DolphinWX/Debugger/JitWindow.cpp | 7 | ||||
| -rw-r--r-- | Source/Core/DolphinWX/Debugger/RegisterView.cpp | 8 |
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; |
