From 990d973c74b37ca51df6b5bf2ae4624cf911477f Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Sun, 27 Dec 2015 22:53:05 -0800 Subject: [PATCH] New ppc opcode decoder. Seems to work and match up with the old decoder (which may be bad). Old decoder remains until all functionality is replaced. --- src/xenia/cpu/ppc/ppc_disasm.cc | 12 +- src/xenia/cpu/ppc/ppc_disasm.h | 3 +- src/xenia/cpu/ppc/ppc_hir_builder.cc | 29 +- src/xenia/cpu/ppc/ppc_opcode.h | 479 +++++++++++++++ src/xenia/cpu/ppc/ppc_opcode_info.h | 79 +++ src/xenia/cpu/ppc/ppc_opcode_lookup.cc | 554 ++++++++++++++++++ src/xenia/cpu/ppc/ppc_opcode_table.cc | 482 +++++++++++++++ src/xenia/cpu/ppc/ppc_scanner.cc | 60 +- src/xenia/cpu/ppc/ppc_translator.cc | 11 +- src/xenia/cpu/ppc/testing/instr_vcmpxxfp128.s | 11 + src/xenia/debug/debugger.cc | 16 +- src/xenia/debug/ui/debug_window.cc | 10 +- src/xenia/kernel/xam/xam_ui.cc | 4 + tools/ppc-instructions.xml | 466 +++++++++++++++ tools/ppc-table-gen.py | 345 +++++++++++ 15 files changed, 2490 insertions(+), 71 deletions(-) create mode 100644 src/xenia/cpu/ppc/ppc_opcode.h create mode 100644 src/xenia/cpu/ppc/ppc_opcode_info.h create mode 100644 src/xenia/cpu/ppc/ppc_opcode_lookup.cc create mode 100644 src/xenia/cpu/ppc/ppc_opcode_table.cc create mode 100644 tools/ppc-instructions.xml create mode 100644 tools/ppc-table-gen.py diff --git a/src/xenia/cpu/ppc/ppc_disasm.cc b/src/xenia/cpu/ppc/ppc_disasm.cc index a815f43d3..97c559073 100644 --- a/src/xenia/cpu/ppc/ppc_disasm.cc +++ b/src/xenia/cpu/ppc/ppc_disasm.cc @@ -11,7 +11,7 @@ #include "xenia/base/assert.h" #include "xenia/base/math.h" -#include "xenia/base/string_buffer.h" +#include "xenia/cpu/ppc/ppc_instr.h" namespace xe { namespace cpu { @@ -505,11 +505,15 @@ void Disasm_vspltisw(InstrData* i, StringBuffer* str) { str->AppendFormat("%-8s v%d, %.8X", i->type->name, i->VX.VD, simm); } -int DisasmPPC(InstrData* i, StringBuffer* str) { - if (!i->type) { +int DisasmPPC(uint32_t address, uint32_t code, StringBuffer* str) { + InstrData i; + i.address = address; + i.code = code; + i.type = GetInstrType(i.code); + if (!i.type) { str->Append("???"); } else { - i->type->disasm(i, str); + i.type->disasm(&i, str); } return 0; } diff --git a/src/xenia/cpu/ppc/ppc_disasm.h b/src/xenia/cpu/ppc/ppc_disasm.h index faf372b47..2f983ee2c 100644 --- a/src/xenia/cpu/ppc/ppc_disasm.h +++ b/src/xenia/cpu/ppc/ppc_disasm.h @@ -11,13 +11,12 @@ #define XENIA_CPU_PPC_PPC_DISASM_H_ #include "xenia/base/string_buffer.h" -#include "xenia/cpu/ppc/ppc_instr.h" namespace xe { namespace cpu { namespace ppc { -int DisasmPPC(InstrData* i, StringBuffer* str); +int DisasmPPC(uint32_t address, uint32_t code, StringBuffer* str); } // namespace ppc } // namespace cpu diff --git a/src/xenia/cpu/ppc/ppc_hir_builder.cc b/src/xenia/cpu/ppc/ppc_hir_builder.cc index e9391cd15..8ec4e1b73 100644 --- a/src/xenia/cpu/ppc/ppc_hir_builder.cc +++ b/src/xenia/cpu/ppc/ppc_hir_builder.cc @@ -21,6 +21,7 @@ #include "xenia/cpu/ppc/ppc_disasm.h" #include "xenia/cpu/ppc/ppc_frontend.h" #include "xenia/cpu/ppc/ppc_instr.h" +#include "xenia/cpu/ppc/ppc_opcode_info.h" #include "xenia/cpu/processor.h" namespace xe { @@ -84,14 +85,13 @@ bool PPCHIRBuilder::Emit(GuestFunction* function, uint32_t flags) { uint32_t start_address = function_->address(); uint32_t end_address = function_->end_address(); - InstrData i; for (uint32_t address = start_address, offset = 0; address <= end_address; address += 4, offset++) { - i.address = address; - i.code = xe::load_and_swap(memory->TranslateVirtual(address)); - // TODO(benvanik): find a way to avoid using the opcode tables. - i.type = GetInstrType(i.code); trace_info_.dest_count = 0; + uint32_t code = + xe::load_and_swap(memory->TranslateVirtual(address)); + auto opcode = LookupOpcode(code); + auto& opcode_info = GetOpcodeInfo(opcode); // Mark label, if we were assigned one earlier on in the walk. // We may still get a label, but it'll be inserted by LookupLabel @@ -107,15 +107,15 @@ bool PPCHIRBuilder::Emit(GuestFunction* function, uint32_t flags) { AnnotateLabel(address, label); } comment_buffer_.Reset(); - comment_buffer_.AppendFormat("%.8X %.8X ", address, i.code); - DisasmPPC(&i, &comment_buffer_); + comment_buffer_.AppendFormat("%.8X %.8X ", address, code); + DisasmPPC(address, code, &comment_buffer_); Comment(comment_buffer_); first_instr = last_instr(); } // Mark source offset for debugging. // We could omit this if we never wanted to debug. - SourceOffset(i.address); + SourceOffset(address); if (!first_instr) { first_instr = last_instr(); } @@ -123,8 +123,13 @@ bool PPCHIRBuilder::Emit(GuestFunction* function, uint32_t flags) { // Stash instruction offset. It's either the SOURCE_OFFSET or the COMMENT. instr_offset_list_[offset] = first_instr; + InstrData i; + i.address = address; + i.code = code; + i.type = GetInstrType(code); + if (!i.type) { - XELOGE("Invalid instruction %.8llX %.8X", i.address, i.code); + XELOGE("Invalid instruction %.8llX %.8X", address, code); Comment("INVALID!"); // TraceInvalidInstruction(i); continue; @@ -141,7 +146,7 @@ bool PPCHIRBuilder::Emit(GuestFunction* function, uint32_t flags) { typedef int (*InstrEmitter)(PPCHIRBuilder& f, InstrData& i); InstrEmitter emit = (InstrEmitter)i.type->emit; - if (i.address == FLAGS_break_on_instruction) { + if (address == FLAGS_break_on_instruction) { Comment("--break-on-instruction target"); if (FLAGS_break_condition_gpr < 0) { @@ -158,8 +163,8 @@ bool PPCHIRBuilder::Emit(GuestFunction* function, uint32_t flags) { } if (!i.type->emit || emit(*this, i)) { - XELOGE("Unimplemented instr %.8llX %.8X %s", i.address, i.code, - i.type->name); + XELOGE("Unimplemented instr %.8llX %.8X %s", address, code, + opcode_info.name); Comment("UNIMPLEMENTED!"); // DebugBreak(); // TraceInvalidInstruction(i); diff --git a/src/xenia/cpu/ppc/ppc_opcode.h b/src/xenia/cpu/ppc/ppc_opcode.h new file mode 100644 index 000000000..ad333260f --- /dev/null +++ b/src/xenia/cpu/ppc/ppc_opcode.h @@ -0,0 +1,479 @@ +// This code was autogenerated by tools/ppc-table-gen.py. Do not modify! +// clang-format off +#ifndef XENIA_CPU_PPC_PPC_OPCODE_H_ +#define XENIA_CPU_PPC_PPC_OPCODE_H_ + +#include + +namespace xe { +namespace cpu { +namespace ppc { + +// All PPC opcodes in the same order they appear in ppc_instr_table.h: +enum class PPCOpcode : uint32_t { + addcx, + addex, + addi, + addic, + addicx, + addis, + addmex, + addx, + addzex, + andcx, + andisx, + andix, + andx, + bcctrx, + bclrx, + bcx, + bx, + cmp, + cmpi, + cmpl, + cmpli, + cntlzdx, + cntlzwx, + crand, + crandc, + creqv, + crnand, + crnor, + cror, + crorc, + crxor, + dcba, + dcbf, + dcbi, + dcbst, + dcbt, + dcbtst, + dcbz, + dcbz128, + divdux, + divdx, + divwux, + divwx, + eciwx, + ecowx, + eieio, + eqvx, + extsbx, + extshx, + extswx, + fabsx, + faddsx, + faddx, + fcfidx, + fcmpo, + fcmpu, + fctidx, + fctidzx, + fctiwx, + fctiwzx, + fdivsx, + fdivx, + fmaddsx, + fmaddx, + fmrx, + fmsubsx, + fmsubx, + fmulsx, + fmulx, + fnabsx, + fnegx, + fnmaddsx, + fnmaddx, + fnmsubsx, + fnmsubx, + fresx, + frspx, + frsqrtex, + fselx, + fsqrtsx, + fsqrtx, + fsubsx, + fsubx, + icbi, + isync, + lbz, + lbzu, + lbzux, + lbzx, + ld, + ldarx, + ldbrx, + ldu, + ldux, + ldx, + lfd, + lfdu, + lfdux, + lfdx, + lfs, + lfsu, + lfsux, + lfsx, + lha, + lhau, + lhaux, + lhax, + lhbrx, + lhz, + lhzu, + lhzux, + lhzx, + lmw, + lswi, + lswx, + lvebx, + lvehx, + lvewx, + lvewx128, + lvlx, + lvlx128, + lvlxl, + lvlxl128, + lvrx, + lvrx128, + lvrxl, + lvrxl128, + lvsl, + lvsl128, + lvsr, + lvsr128, + lvx, + lvx128, + lvxl, + lvxl128, + lwa, + lwarx, + lwaux, + lwax, + lwbrx, + lwz, + lwzu, + lwzux, + lwzx, + mcrf, + mcrfs, + mcrxr, + mfcr, + mffsx, + mfmsr, + mfspr, + mftb, + mfvscr, + mtcrf, + mtfsb0x, + mtfsb1x, + mtfsfix, + mtfsfx, + mtmsr, + mtmsrd, + mtspr, + mtvscr, + mulhdux, + mulhdx, + mulhwux, + mulhwx, + mulldx, + mulli, + mullwx, + nandx, + negx, + norx, + orcx, + ori, + oris, + orx, + rldclx, + rldcrx, + rldiclx, + rldicrx, + rldicx, + rldimix, + rlwimix, + rlwinmx, + rlwnmx, + sc, + sldx, + slwx, + sradix, + sradx, + srawix, + srawx, + srdx, + srwx, + stb, + stbu, + stbux, + stbx, + std, + stdbrx, + stdcx, + stdu, + stdux, + stdx, + stfd, + stfdu, + stfdux, + stfdx, + stfiwx, + stfs, + stfsu, + stfsux, + stfsx, + sth, + sthbrx, + sthu, + sthux, + sthx, + stmw, + stswi, + stswx, + stvebx, + stvehx, + stvewx, + stvewx128, + stvlx, + stvlx128, + stvlxl, + stvlxl128, + stvrx, + stvrx128, + stvrxl, + stvrxl128, + stvx, + stvx128, + stvxl, + stvxl128, + stw, + stwbrx, + stwcx, + stwu, + stwux, + stwx, + subfcx, + subfex, + subficx, + subfmex, + subfx, + subfzex, + sync, + td, + tdi, + tw, + twi, + vaddcuw, + vaddfp, + vaddfp128, + vaddsbs, + vaddshs, + vaddsws, + vaddubm, + vaddubs, + vadduhm, + vadduhs, + vadduwm, + vadduws, + vand, + vand128, + vandc, + vandc128, + vavgsb, + vavgsh, + vavgsw, + vavgub, + vavguh, + vavguw, + vcfpsxws128, + vcfpuxws128, + vcfsx, + vcfux, + vcmpbfp, + vcmpbfp128, + vcmpeqfp, + vcmpeqfp128, + vcmpequb, + vcmpequh, + vcmpequw, + vcmpequw128, + vcmpgefp, + vcmpgefp128, + vcmpgtfp, + vcmpgtfp128, + vcmpgtsb, + vcmpgtsh, + vcmpgtsw, + vcmpgtub, + vcmpgtuh, + vcmpgtuw, + vcsxwfp128, + vctsxs, + vctuxs, + vcuxwfp128, + vexptefp, + vexptefp128, + vlogefp, + vlogefp128, + vmaddcfp128, + vmaddfp, + vmaddfp128, + vmaxfp, + vmaxfp128, + vmaxsb, + vmaxsh, + vmaxsw, + vmaxub, + vmaxuh, + vmaxuw, + vmhaddshs, + vmhraddshs, + vminfp, + vminfp128, + vminsb, + vminsh, + vminsw, + vminub, + vminuh, + vminuw, + vmladduhm, + vmrghb, + vmrghh, + vmrghw, + vmrghw128, + vmrglb, + vmrglh, + vmrglw, + vmrglw128, + vmsum3fp128, + vmsum4fp128, + vmsummbm, + vmsumshm, + vmsumshs, + vmsumubm, + vmsumuhm, + vmsumuhs, + vmulesb, + vmulesh, + vmuleub, + vmuleuh, + vmulfp128, + vmulosb, + vmulosh, + vmuloub, + vmulouh, + vnmsubfp, + vnmsubfp128, + vnor, + vnor128, + vor, + vor128, + vperm, + vperm128, + vpermwi128, + vpkd3d128, + vpkpx, + vpkshss, + vpkshss128, + vpkshus, + vpkshus128, + vpkswss, + vpkswss128, + vpkswus, + vpkswus128, + vpkuhum, + vpkuhum128, + vpkuhus, + vpkuhus128, + vpkuwum, + vpkuwum128, + vpkuwus, + vpkuwus128, + vrefp, + vrefp128, + vrfim, + vrfim128, + vrfin, + vrfin128, + vrfip, + vrfip128, + vrfiz, + vrfiz128, + vrlb, + vrlh, + vrlimi128, + vrlw, + vrlw128, + vrsqrtefp, + vrsqrtefp128, + vsel, + vsel128, + vsl, + vslb, + vsldoi, + vsldoi128, + vslh, + vslo, + vslo128, + vslw, + vslw128, + vspltb, + vsplth, + vspltisb, + vspltish, + vspltisw, + vspltisw128, + vspltw, + vspltw128, + vsr, + vsrab, + vsrah, + vsraw, + vsraw128, + vsrb, + vsrh, + vsro, + vsro128, + vsrw, + vsrw128, + vsubcuw, + vsubfp, + vsubfp128, + vsubsbs, + vsubshs, + vsubsws, + vsububm, + vsububs, + vsubuhm, + vsubuhs, + vsubuwm, + vsubuws, + vsum2sws, + vsum4sbs, + vsum4shs, + vsum4ubs, + vsumsws, + vupkd3d128, + vupkhpx, + vupkhsb, + vupkhsb128, + vupkhsh, + vupklpx, + vupklsb, + vupklsb128, + vupklsh, + vxor, + vxor128, + xori, + xoris, + xorx, + kInvalid, +}; + +} // namespace ppc +} // namespace cpu +} // namespace xe + +#endif // XENIA_CPU_PPC_PPC_OPCODE_H_ diff --git a/src/xenia/cpu/ppc/ppc_opcode_info.h b/src/xenia/cpu/ppc/ppc_opcode_info.h new file mode 100644 index 000000000..4ed16c11d --- /dev/null +++ b/src/xenia/cpu/ppc/ppc_opcode_info.h @@ -0,0 +1,79 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2015 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_CPU_PPC_PPC_OPCODE_INFO_H_ +#define XENIA_CPU_PPC_PPC_OPCODE_INFO_H_ + +#include + +#include "xenia/cpu/ppc/ppc_opcode.h" + +namespace xe { +namespace cpu { +namespace ppc { + +enum class PPCOpcodeFormat { + kSC, + kD, + kB, + kI, + kX, + kXL, + kXFX, + kXFL, + kVX, + kVX128, + kVX128_1, + kVX128_2, + kVX128_3, + kVX128_4, + kVX128_5, + kVX128_R, + kVX128_P, + kVC, + kVA, + kXO, + kXW, + kA, + kDS, + kM, + kMD, + kMDS, + kMDSH, + kXS, + kDCBZ, +}; + +enum class PPCOpcodeGroup { + kInt, + kFp, + kVmx, +}; + +struct PPCOpcodeInfo { + uint32_t opcode; + const char* name; + PPCOpcodeFormat format; + PPCOpcodeGroup group; + const char* description; +}; + +PPCOpcode LookupOpcode(uint32_t code); + +const PPCOpcodeInfo& GetOpcodeInfo(PPCOpcode opcode); + +inline const PPCOpcodeInfo& LookupOpcodeInfo(uint32_t code) { + return GetOpcodeInfo(LookupOpcode(code)); +} + +} // namespace ppc +} // namespace cpu +} // namespace xe + +#endif // XENIA_CPU_PPC_PPC_OPCODE_INFO_H_ diff --git a/src/xenia/cpu/ppc/ppc_opcode_lookup.cc b/src/xenia/cpu/ppc/ppc_opcode_lookup.cc new file mode 100644 index 000000000..27857665e --- /dev/null +++ b/src/xenia/cpu/ppc/ppc_opcode_lookup.cc @@ -0,0 +1,554 @@ +// This code was autogenerated by tools/ppc-table-gen.py. Do not modify! +// clang-format off +#include + +#include "xenia/base/assert.h" +#include "xenia/cpu/ppc/ppc_opcode.h" +#include "xenia/cpu/ppc/ppc_opcode_info.h" + +namespace xe { +namespace cpu { +namespace ppc { + +constexpr uint32_t ExtractBits(uint32_t v, uint32_t a, uint32_t b) { + return (v >> (32 - 1 - b)) & ((1 << (b - a + 1)) - 1); +} + +#define PPC_DECODER_MISS assert_always(); return PPCOpcode::kInvalid +#define PPC_DECODER_HIT(name) return PPCOpcode::name; + +PPCOpcode LookupOpcode(uint32_t code) { + switch (ExtractBits(code, 0, 5)) { + case 2: PPC_DECODER_HIT(tdi); + case 3: PPC_DECODER_HIT(twi); + case 4: + switch ((ExtractBits(code, 21, 27) << 4)|(ExtractBits(code, 30, 31) << 0)) { + case 0b00000000011: PPC_DECODER_HIT(lvsl128); + case 0b00001000011: PPC_DECODER_HIT(lvsr128); + case 0b00010000011: PPC_DECODER_HIT(lvewx128); + case 0b00011000011: PPC_DECODER_HIT(lvx128); + case 0b00110000011: PPC_DECODER_HIT(stvewx128); + case 0b00111000011: PPC_DECODER_HIT(stvx128); + case 0b01011000011: PPC_DECODER_HIT(lvxl128); + case 0b01111000011: PPC_DECODER_HIT(stvxl128); + case 0b10000000011: PPC_DECODER_HIT(lvlx128); + case 0b10001000011: PPC_DECODER_HIT(lvrx128); + case 0b10100000011: PPC_DECODER_HIT(stvlx128); + case 0b10101000011: PPC_DECODER_HIT(stvrx128); + case 0b11000000011: PPC_DECODER_HIT(lvlxl128); + case 0b11001000011: PPC_DECODER_HIT(lvrxl128); + case 0b11100000011: PPC_DECODER_HIT(stvlxl128); + case 0b11101000011: PPC_DECODER_HIT(stvrxl128); + } + switch ((ExtractBits(code, 21, 31) << 0)) { + case 0b00000000000: PPC_DECODER_HIT(vaddubm); + case 0b00000000010: PPC_DECODER_HIT(vmaxub); + case 0b00000000100: PPC_DECODER_HIT(vrlb); + case 0b00000001000: PPC_DECODER_HIT(vmuloub); + case 0b00000001010: PPC_DECODER_HIT(vaddfp); + case 0b00000001100: PPC_DECODER_HIT(vmrghb); + case 0b00000001110: PPC_DECODER_HIT(vpkuhum); + case 0b00001000000: PPC_DECODER_HIT(vadduhm); + case 0b00001000010: PPC_DECODER_HIT(vmaxuh); + case 0b00001000100: PPC_DECODER_HIT(vrlh); + case 0b00001001000: PPC_DECODER_HIT(vmulouh); + case 0b00001001010: PPC_DECODER_HIT(vsubfp); + case 0b00001001100: PPC_DECODER_HIT(vmrghh); + case 0b00001001110: PPC_DECODER_HIT(vpkuwum); + case 0b00010000000: PPC_DECODER_HIT(vadduwm); + case 0b00010000010: PPC_DECODER_HIT(vmaxuw); + case 0b00010000100: PPC_DECODER_HIT(vrlw); + case 0b00010001100: PPC_DECODER_HIT(vmrghw); + case 0b00010001110: PPC_DECODER_HIT(vpkuhus); + case 0b00011001110: PPC_DECODER_HIT(vpkuwus); + case 0b00100000010: PPC_DECODER_HIT(vmaxsb); + case 0b00100000100: PPC_DECODER_HIT(vslb); + case 0b00100001000: PPC_DECODER_HIT(vmulosb); + case 0b00100001010: PPC_DECODER_HIT(vrefp); + case 0b00100001100: PPC_DECODER_HIT(vmrglb); + case 0b00100001110: PPC_DECODER_HIT(vpkshus); + case 0b00101000010: PPC_DECODER_HIT(vmaxsh); + case 0b00101000100: PPC_DECODER_HIT(vslh); + case 0b00101001000: PPC_DECODER_HIT(vmulosh); + case 0b00101001010: PPC_DECODER_HIT(vrsqrtefp); + case 0b00101001100: PPC_DECODER_HIT(vmrglh); + case 0b00101001110: PPC_DECODER_HIT(vpkswus); + case 0b00110000000: PPC_DECODER_HIT(vaddcuw); + case 0b00110000010: PPC_DECODER_HIT(vmaxsw); + case 0b00110000100: PPC_DECODER_HIT(vslw); + case 0b00110001010: PPC_DECODER_HIT(vexptefp); + case 0b00110001100: PPC_DECODER_HIT(vmrglw); + case 0b00110001110: PPC_DECODER_HIT(vpkshss); + case 0b00111000100: PPC_DECODER_HIT(vsl); + case 0b00111001010: PPC_DECODER_HIT(vlogefp); + case 0b00111001110: PPC_DECODER_HIT(vpkswss); + case 0b01000000000: PPC_DECODER_HIT(vaddubs); + case 0b01000000010: PPC_DECODER_HIT(vminub); + case 0b01000000100: PPC_DECODER_HIT(vsrb); + case 0b01000001000: PPC_DECODER_HIT(vmuleub); + case 0b01000001010: PPC_DECODER_HIT(vrfin); + case 0b01000001100: PPC_DECODER_HIT(vspltb); + case 0b01000001110: PPC_DECODER_HIT(vupkhsb); + case 0b01001000000: PPC_DECODER_HIT(vadduhs); + case 0b01001000010: PPC_DECODER_HIT(vminuh); + case 0b01001000100: PPC_DECODER_HIT(vsrh); + case 0b01001001000: PPC_DECODER_HIT(vmuleuh); + case 0b01001001010: PPC_DECODER_HIT(vrfiz); + case 0b01001001100: PPC_DECODER_HIT(vsplth); + case 0b01001001110: PPC_DECODER_HIT(vupkhsh); + case 0b01010000000: PPC_DECODER_HIT(vadduws); + case 0b01010000010: PPC_DECODER_HIT(vminuw); + case 0b01010000100: PPC_DECODER_HIT(vsrw); + case 0b01010001010: PPC_DECODER_HIT(vrfip); + case 0b01010001100: PPC_DECODER_HIT(vspltw); + case 0b01010001110: PPC_DECODER_HIT(vupklsb); + case 0b01011000100: PPC_DECODER_HIT(vsr); + case 0b01011001010: PPC_DECODER_HIT(vrfim); + case 0b01011001110: PPC_DECODER_HIT(vupklsh); + case 0b01100000000: PPC_DECODER_HIT(vaddsbs); + case 0b01100000010: PPC_DECODER_HIT(vminsb); + case 0b01100000100: PPC_DECODER_HIT(vsrab); + case 0b01100001000: PPC_DECODER_HIT(vmulesb); + case 0b01100001010: PPC_DECODER_HIT(vcfux); + case 0b01100001100: PPC_DECODER_HIT(vspltisb); + case 0b01100001110: PPC_DECODER_HIT(vpkpx); + case 0b01101000000: PPC_DECODER_HIT(vaddshs); + case 0b01101000010: PPC_DECODER_HIT(vminsh); + case 0b01101000100: PPC_DECODER_HIT(vsrah); + case 0b01101001000: PPC_DECODER_HIT(vmulesh); + case 0b01101001010: PPC_DECODER_HIT(vcfsx); + case 0b01101001100: PPC_DECODER_HIT(vspltish); + case 0b01101001110: PPC_DECODER_HIT(vupkhpx); + case 0b01110000000: PPC_DECODER_HIT(vaddsws); + case 0b01110000010: PPC_DECODER_HIT(vminsw); + case 0b01110000100: PPC_DECODER_HIT(vsraw); + case 0b01110001010: PPC_DECODER_HIT(vctuxs); + case 0b01110001100: PPC_DECODER_HIT(vspltisw); + case 0b01111001010: PPC_DECODER_HIT(vctsxs); + case 0b01111001110: PPC_DECODER_HIT(vupklpx); + case 0b10000000000: PPC_DECODER_HIT(vsububm); + case 0b10000000010: PPC_DECODER_HIT(vavgub); + case 0b10000000100: PPC_DECODER_HIT(vand); + case 0b10000001010: PPC_DECODER_HIT(vmaxfp); + case 0b10000001100: PPC_DECODER_HIT(vslo); + case 0b10001000000: PPC_DECODER_HIT(vsubuhm); + case 0b10001000010: PPC_DECODER_HIT(vavguh); + case 0b10001000100: PPC_DECODER_HIT(vandc); + case 0b10001001010: PPC_DECODER_HIT(vminfp); + case 0b10001001100: PPC_DECODER_HIT(vsro); + case 0b10010000000: PPC_DECODER_HIT(vsubuwm); + case 0b10010000010: PPC_DECODER_HIT(vavguw); + case 0b10010000100: PPC_DECODER_HIT(vor); + case 0b10011000100: PPC_DECODER_HIT(vxor); + case 0b10100000010: PPC_DECODER_HIT(vavgsb); + case 0b10100000100: PPC_DECODER_HIT(vnor); + case 0b10101000010: PPC_DECODER_HIT(vavgsh); + case 0b10110000000: PPC_DECODER_HIT(vsubcuw); + case 0b10110000010: PPC_DECODER_HIT(vavgsw); + case 0b11000000000: PPC_DECODER_HIT(vsububs); + case 0b11000000100: PPC_DECODER_HIT(mfvscr); + case 0b11000001000: PPC_DECODER_HIT(vsum4ubs); + case 0b11001000000: PPC_DECODER_HIT(vsubuhs); + case 0b11001000100: PPC_DECODER_HIT(mtvscr); + case 0b11001001000: PPC_DECODER_HIT(vsum4shs); + case 0b11010000000: PPC_DECODER_HIT(vsubuws); + case 0b11010001000: PPC_DECODER_HIT(vsum2sws); + case 0b11100000000: PPC_DECODER_HIT(vsubsbs); + case 0b11100001000: PPC_DECODER_HIT(vsum4sbs); + case 0b11101000000: PPC_DECODER_HIT(vsubshs); + case 0b11110000000: PPC_DECODER_HIT(vsubsws); + case 0b11110001000: PPC_DECODER_HIT(vsumsws); + } + switch ((ExtractBits(code, 22, 31) << 0)) { + case 0b0000000110: PPC_DECODER_HIT(vcmpequb); + case 0b0001000110: PPC_DECODER_HIT(vcmpequh); + case 0b0010000110: PPC_DECODER_HIT(vcmpequw); + case 0b0011000110: PPC_DECODER_HIT(vcmpeqfp); + case 0b0111000110: PPC_DECODER_HIT(vcmpgefp); + case 0b1000000110: PPC_DECODER_HIT(vcmpgtub); + case 0b1001000110: PPC_DECODER_HIT(vcmpgtuh); + case 0b1010000110: PPC_DECODER_HIT(vcmpgtuw); + case 0b1011000110: PPC_DECODER_HIT(vcmpgtfp); + case 0b1100000110: PPC_DECODER_HIT(vcmpgtsb); + case 0b1101000110: PPC_DECODER_HIT(vcmpgtsh); + case 0b1110000110: PPC_DECODER_HIT(vcmpgtsw); + case 0b1111000110: PPC_DECODER_HIT(vcmpbfp); + } + switch ((ExtractBits(code, 26, 31) << 0)) { + case 0b100000: PPC_DECODER_HIT(vmhaddshs); + case 0b100001: PPC_DECODER_HIT(vmhraddshs); + case 0b100010: PPC_DECODER_HIT(vmladduhm); + case 0b100100: PPC_DECODER_HIT(vmsumubm); + case 0b100101: PPC_DECODER_HIT(vmsummbm); + case 0b100110: PPC_DECODER_HIT(vmsumuhm); + case 0b100111: PPC_DECODER_HIT(vmsumuhs); + case 0b101000: PPC_DECODER_HIT(vmsumshm); + case 0b101001: PPC_DECODER_HIT(vmsumshs); + case 0b101010: PPC_DECODER_HIT(vsel); + case 0b101011: PPC_DECODER_HIT(vperm); + case 0b101100: PPC_DECODER_HIT(vsldoi); + case 0b101110: PPC_DECODER_HIT(vmaddfp); + case 0b101111: PPC_DECODER_HIT(vnmsubfp); + } + switch ((ExtractBits(code, 27, 27) << 0)) { + case 0b1: PPC_DECODER_HIT(vsldoi128); + } + PPC_DECODER_MISS; + case 5: + switch ((ExtractBits(code, 22, 22) << 5)|(ExtractBits(code, 27, 27) << 0)) { + case 0b000000: PPC_DECODER_HIT(vperm128); + } + switch ((ExtractBits(code, 22, 25) << 2)|(ExtractBits(code, 27, 27) << 0)) { + case 0b000001: PPC_DECODER_HIT(vaddfp128); + case 0b000101: PPC_DECODER_HIT(vsubfp128); + case 0b001001: PPC_DECODER_HIT(vmulfp128); + case 0b001101: PPC_DECODER_HIT(vmaddfp128); + case 0b010001: PPC_DECODER_HIT(vmaddcfp128); + case 0b010101: PPC_DECODER_HIT(vnmsubfp128); + case 0b011001: PPC_DECODER_HIT(vmsum3fp128); + case 0b011101: PPC_DECODER_HIT(vmsum4fp128); + case 0b100000: PPC_DECODER_HIT(vpkshss128); + case 0b100001: PPC_DECODER_HIT(vand128); + case 0b100100: PPC_DECODER_HIT(vpkshus128); + case 0b100101: PPC_DECODER_HIT(vandc128); + case 0b101000: PPC_DECODER_HIT(vpkswss128); + case 0b101001: PPC_DECODER_HIT(vnor128); + case 0b101100: PPC_DECODER_HIT(vpkswus128); + case 0b101101: PPC_DECODER_HIT(vor128); + case 0b110000: PPC_DECODER_HIT(vpkuhum128); + case 0b110001: PPC_DECODER_HIT(vxor128); + case 0b110100: PPC_DECODER_HIT(vpkuhus128); + case 0b110101: PPC_DECODER_HIT(vsel128); + case 0b111000: PPC_DECODER_HIT(vpkuwum128); + case 0b111001: PPC_DECODER_HIT(vslo128); + case 0b111100: PPC_DECODER_HIT(vpkuwus128); + case 0b111101: PPC_DECODER_HIT(vsro128); + } + PPC_DECODER_MISS; + case 6: + switch ((ExtractBits(code, 21, 22) << 5)|(ExtractBits(code, 26, 27) << 0)) { + case 0b0100001: PPC_DECODER_HIT(vpermwi128); + } + switch ((ExtractBits(code, 21, 23) << 4)|(ExtractBits(code, 26, 27) << 0)) { + case 0b1100001: PPC_DECODER_HIT(vpkd3d128); + case 0b1110001: PPC_DECODER_HIT(vrlimi128); + } + switch ((ExtractBits(code, 21, 27) << 0)) { + case 0b0100011: PPC_DECODER_HIT(vcfpsxws128); + case 0b0100111: PPC_DECODER_HIT(vcfpuxws128); + case 0b0101011: PPC_DECODER_HIT(vcsxwfp128); + case 0b0101111: PPC_DECODER_HIT(vcuxwfp128); + case 0b0110011: PPC_DECODER_HIT(vrfim128); + case 0b0110111: PPC_DECODER_HIT(vrfin128); + case 0b0111011: PPC_DECODER_HIT(vrfip128); + case 0b0111111: PPC_DECODER_HIT(vrfiz128); + case 0b1100011: PPC_DECODER_HIT(vrefp128); + case 0b1100111: PPC_DECODER_HIT(vrsqrtefp128); + case 0b1101011: PPC_DECODER_HIT(vexptefp128); + case 0b1101111: PPC_DECODER_HIT(vlogefp128); + case 0b1110011: PPC_DECODER_HIT(vspltw128); + case 0b1110111: PPC_DECODER_HIT(vspltisw128); + case 0b1111111: PPC_DECODER_HIT(vupkd3d128); + } + switch ((ExtractBits(code, 22, 24) << 3)|(ExtractBits(code, 27, 27) << 0)) { + case 0b000000: PPC_DECODER_HIT(vcmpeqfp128); + case 0b001000: PPC_DECODER_HIT(vcmpgefp128); + case 0b010000: PPC_DECODER_HIT(vcmpgtfp128); + case 0b011000: PPC_DECODER_HIT(vcmpbfp128); + case 0b100000: PPC_DECODER_HIT(vcmpequw128); + } + switch ((ExtractBits(code, 22, 25) << 2)|(ExtractBits(code, 27, 27) << 0)) { + case 0b000101: PPC_DECODER_HIT(vrlw128); + case 0b001101: PPC_DECODER_HIT(vslw128); + case 0b010101: PPC_DECODER_HIT(vsraw128); + case 0b011101: PPC_DECODER_HIT(vsrw128); + case 0b101000: PPC_DECODER_HIT(vmaxfp128); + case 0b101100: PPC_DECODER_HIT(vminfp128); + case 0b110000: PPC_DECODER_HIT(vmrghw128); + case 0b110100: PPC_DECODER_HIT(vmrglw128); + case 0b111000: PPC_DECODER_HIT(vupkhsb128); + case 0b111100: PPC_DECODER_HIT(vupklsb128); + } + PPC_DECODER_MISS; + case 7: PPC_DECODER_HIT(mulli); + case 8: PPC_DECODER_HIT(subficx); + case 10: PPC_DECODER_HIT(cmpli); + case 11: PPC_DECODER_HIT(cmpi); + case 12: PPC_DECODER_HIT(addic); + case 13: PPC_DECODER_HIT(addicx); + case 14: PPC_DECODER_HIT(addi); + case 15: PPC_DECODER_HIT(addis); + case 16: PPC_DECODER_HIT(bcx); + case 17: PPC_DECODER_HIT(sc); + case 18: PPC_DECODER_HIT(bx); + case 19: + switch ((ExtractBits(code, 21, 30) << 0)) { + case 0b0000000000: PPC_DECODER_HIT(mcrf); + case 0b0000010000: PPC_DECODER_HIT(bclrx); + case 0b0000100001: PPC_DECODER_HIT(crnor); + case 0b0010000001: PPC_DECODER_HIT(crandc); + case 0b0010010110: PPC_DECODER_HIT(isync); + case 0b0011000001: PPC_DECODER_HIT(crxor); + case 0b0011100001: PPC_DECODER_HIT(crnand); + case 0b0100000001: PPC_DECODER_HIT(crand); + case 0b0100100001: PPC_DECODER_HIT(creqv); + case 0b0110100001: PPC_DECODER_HIT(crorc); + case 0b0111000001: PPC_DECODER_HIT(cror); + case 0b1000010000: PPC_DECODER_HIT(bcctrx); + } + PPC_DECODER_MISS; + case 20: PPC_DECODER_HIT(rlwimix); + case 21: PPC_DECODER_HIT(rlwinmx); + case 23: PPC_DECODER_HIT(rlwnmx); + case 24: PPC_DECODER_HIT(ori); + case 25: PPC_DECODER_HIT(oris); + case 26: PPC_DECODER_HIT(xori); + case 27: PPC_DECODER_HIT(xoris); + case 28: PPC_DECODER_HIT(andix); + case 29: PPC_DECODER_HIT(andisx); + case 30: + switch ((ExtractBits(code, 27, 29) << 0)) { + case 0b000: PPC_DECODER_HIT(rldiclx); + case 0b001: PPC_DECODER_HIT(rldicrx); + case 0b010: PPC_DECODER_HIT(rldicx); + case 0b011: PPC_DECODER_HIT(rldimix); + } + switch ((ExtractBits(code, 27, 30) << 0)) { + case 0b1000: PPC_DECODER_HIT(rldclx); + case 0b1001: PPC_DECODER_HIT(rldcrx); + } + PPC_DECODER_MISS; + case 31: + switch ((ExtractBits(code, 21, 29) << 0)) { + case 0b110011101: PPC_DECODER_HIT(sradix); + } + switch ((ExtractBits(code, 21, 30) << 0)) { + case 0b0000000000: PPC_DECODER_HIT(cmp); + case 0b0000000100: PPC_DECODER_HIT(tw); + case 0b0000000110: PPC_DECODER_HIT(lvsl); + case 0b0000000111: PPC_DECODER_HIT(lvebx); + case 0b0000010011: PPC_DECODER_HIT(mfcr); + case 0b0000010100: PPC_DECODER_HIT(lwarx); + case 0b0000010101: PPC_DECODER_HIT(ldx); + case 0b0000010111: PPC_DECODER_HIT(lwzx); + case 0b0000011000: PPC_DECODER_HIT(slwx); + case 0b0000011010: PPC_DECODER_HIT(cntlzwx); + case 0b0000011011: PPC_DECODER_HIT(sldx); + case 0b0000011100: PPC_DECODER_HIT(andx); + case 0b0000100000: PPC_DECODER_HIT(cmpl); + case 0b0000100110: PPC_DECODER_HIT(lvsr); + case 0b0000100111: PPC_DECODER_HIT(lvehx); + case 0b0000110101: PPC_DECODER_HIT(ldux); + case 0b0000110110: PPC_DECODER_HIT(dcbst); + case 0b0000110111: PPC_DECODER_HIT(lwzux); + case 0b0000111010: PPC_DECODER_HIT(cntlzdx); + case 0b0000111100: PPC_DECODER_HIT(andcx); + case 0b0001000100: PPC_DECODER_HIT(td); + case 0b0001000111: PPC_DECODER_HIT(lvewx); + case 0b0001010011: PPC_DECODER_HIT(mfmsr); + case 0b0001010100: PPC_DECODER_HIT(ldarx); + case 0b0001010110: PPC_DECODER_HIT(dcbf); + case 0b0001010111: PPC_DECODER_HIT(lbzx); + case 0b0001100111: PPC_DECODER_HIT(lvx); + case 0b0001110111: PPC_DECODER_HIT(lbzux); + case 0b0001111100: PPC_DECODER_HIT(norx); + case 0b0010000111: PPC_DECODER_HIT(stvebx); + case 0b0010010000: PPC_DECODER_HIT(mtcrf); + case 0b0010010010: PPC_DECODER_HIT(mtmsr); + case 0b0010010101: PPC_DECODER_HIT(stdx); + case 0b0010010110: PPC_DECODER_HIT(stwcx); + case 0b0010010111: PPC_DECODER_HIT(stwx); + case 0b0010100111: PPC_DECODER_HIT(stvehx); + case 0b0010110010: PPC_DECODER_HIT(mtmsrd); + case 0b0010110101: PPC_DECODER_HIT(stdux); + case 0b0010110111: PPC_DECODER_HIT(stwux); + case 0b0011000111: PPC_DECODER_HIT(stvewx); + case 0b0011010110: PPC_DECODER_HIT(stdcx); + case 0b0011010111: PPC_DECODER_HIT(stbx); + case 0b0011100111: PPC_DECODER_HIT(stvx); + case 0b0011110110: PPC_DECODER_HIT(dcbtst); + case 0b0011110111: PPC_DECODER_HIT(stbux); + case 0b0100010110: PPC_DECODER_HIT(dcbt); + case 0b0100010111: PPC_DECODER_HIT(lhzx); + case 0b0100011100: PPC_DECODER_HIT(eqvx); + case 0b0100110110: PPC_DECODER_HIT(eciwx); + case 0b0100110111: PPC_DECODER_HIT(lhzux); + case 0b0100111100: PPC_DECODER_HIT(xorx); + case 0b0101010011: PPC_DECODER_HIT(mfspr); + case 0b0101010101: PPC_DECODER_HIT(lwax); + case 0b0101010111: PPC_DECODER_HIT(lhax); + case 0b0101100111: PPC_DECODER_HIT(lvxl); + case 0b0101110011: PPC_DECODER_HIT(mftb); + case 0b0101110101: PPC_DECODER_HIT(lwaux); + case 0b0101110111: PPC_DECODER_HIT(lhaux); + case 0b0110010111: PPC_DECODER_HIT(sthx); + case 0b0110011100: PPC_DECODER_HIT(orcx); + case 0b0110110110: PPC_DECODER_HIT(ecowx); + case 0b0110110111: PPC_DECODER_HIT(sthux); + case 0b0110111100: PPC_DECODER_HIT(orx); + case 0b0111010011: PPC_DECODER_HIT(mtspr); + case 0b0111010110: PPC_DECODER_HIT(dcbi); + case 0b0111011100: PPC_DECODER_HIT(nandx); + case 0b0111100111: PPC_DECODER_HIT(stvxl); + case 0b1000000000: PPC_DECODER_HIT(mcrxr); + case 0b1000000111: PPC_DECODER_HIT(lvlx); + case 0b1000010100: PPC_DECODER_HIT(ldbrx); + case 0b1000010101: PPC_DECODER_HIT(lswx); + case 0b1000010110: PPC_DECODER_HIT(lwbrx); + case 0b1000010111: PPC_DECODER_HIT(lfsx); + case 0b1000011000: PPC_DECODER_HIT(srwx); + case 0b1000011011: PPC_DECODER_HIT(srdx); + case 0b1000100111: PPC_DECODER_HIT(lvrx); + case 0b1000110111: PPC_DECODER_HIT(lfsux); + case 0b1001010101: PPC_DECODER_HIT(lswi); + case 0b1001010110: PPC_DECODER_HIT(sync); + case 0b1001010111: PPC_DECODER_HIT(lfdx); + case 0b1001110111: PPC_DECODER_HIT(lfdux); + case 0b1010000111: PPC_DECODER_HIT(stvlx); + case 0b1010010100: PPC_DECODER_HIT(stdbrx); + case 0b1010010101: PPC_DECODER_HIT(stswx); + case 0b1010010110: PPC_DECODER_HIT(stwbrx); + case 0b1010010111: PPC_DECODER_HIT(stfsx); + case 0b1010100111: PPC_DECODER_HIT(stvrx); + case 0b1010110111: PPC_DECODER_HIT(stfsux); + case 0b1011010101: PPC_DECODER_HIT(stswi); + case 0b1011010111: PPC_DECODER_HIT(stfdx); + case 0b1011110110: PPC_DECODER_HIT(dcba); + case 0b1011110111: PPC_DECODER_HIT(stfdux); + case 0b1100000111: PPC_DECODER_HIT(lvlxl); + case 0b1100010110: PPC_DECODER_HIT(lhbrx); + case 0b1100011000: PPC_DECODER_HIT(srawx); + case 0b1100011010: PPC_DECODER_HIT(sradx); + case 0b1100100111: PPC_DECODER_HIT(lvrxl); + case 0b1100111000: PPC_DECODER_HIT(srawix); + case 0b1101010110: PPC_DECODER_HIT(eieio); + case 0b1110000111: PPC_DECODER_HIT(stvlxl); + case 0b1110010110: PPC_DECODER_HIT(sthbrx); + case 0b1110011010: PPC_DECODER_HIT(extshx); + case 0b1110100111: PPC_DECODER_HIT(stvrxl); + case 0b1110111010: PPC_DECODER_HIT(extsbx); + case 0b1111010110: PPC_DECODER_HIT(icbi); + case 0b1111010111: PPC_DECODER_HIT(stfiwx); + case 0b1111011010: PPC_DECODER_HIT(extswx); + } + switch ((ExtractBits(code, 22, 30) << 0)) { + case 0b000001000: PPC_DECODER_HIT(subfcx); + case 0b000001001: PPC_DECODER_HIT(mulhdux); + case 0b000001010: PPC_DECODER_HIT(addcx); + case 0b000001011: PPC_DECODER_HIT(mulhwux); + case 0b000101000: PPC_DECODER_HIT(subfx); + case 0b001001001: PPC_DECODER_HIT(mulhdx); + case 0b001001011: PPC_DECODER_HIT(mulhwx); + case 0b001101000: PPC_DECODER_HIT(negx); + case 0b010001000: PPC_DECODER_HIT(subfex); + case 0b010001010: PPC_DECODER_HIT(addex); + case 0b011001000: PPC_DECODER_HIT(subfzex); + case 0b011001010: PPC_DECODER_HIT(addzex); + case 0b011101000: PPC_DECODER_HIT(subfmex); + case 0b011101001: PPC_DECODER_HIT(mulldx); + case 0b011101010: PPC_DECODER_HIT(addmex); + case 0b011101011: PPC_DECODER_HIT(mullwx); + case 0b100001010: PPC_DECODER_HIT(addx); + case 0b111001001: PPC_DECODER_HIT(divdux); + case 0b111001011: PPC_DECODER_HIT(divwux); + case 0b111101001: PPC_DECODER_HIT(divdx); + case 0b111101011: PPC_DECODER_HIT(divwx); + } + switch ((ExtractBits(code, 6, 10) << 20)|(ExtractBits(code, 21, 30) << 0)) { + case 0b0000000000000001111110110: PPC_DECODER_HIT(dcbz); + case 0b0000100000000001111110110: PPC_DECODER_HIT(dcbz128); + } + PPC_DECODER_MISS; + case 32: PPC_DECODER_HIT(lwz); + case 33: PPC_DECODER_HIT(lwzu); + case 34: PPC_DECODER_HIT(lbz); + case 35: PPC_DECODER_HIT(lbzu); + case 36: PPC_DECODER_HIT(stw); + case 37: PPC_DECODER_HIT(stwu); + case 38: PPC_DECODER_HIT(stb); + case 39: PPC_DECODER_HIT(stbu); + case 40: PPC_DECODER_HIT(lhz); + case 41: PPC_DECODER_HIT(lhzu); + case 42: PPC_DECODER_HIT(lha); + case 43: PPC_DECODER_HIT(lhau); + case 44: PPC_DECODER_HIT(sth); + case 45: PPC_DECODER_HIT(sthu); + case 46: PPC_DECODER_HIT(lmw); + case 47: PPC_DECODER_HIT(stmw); + case 48: PPC_DECODER_HIT(lfs); + case 49: PPC_DECODER_HIT(lfsu); + case 50: PPC_DECODER_HIT(lfd); + case 51: PPC_DECODER_HIT(lfdu); + case 52: PPC_DECODER_HIT(stfs); + case 53: PPC_DECODER_HIT(stfsu); + case 54: PPC_DECODER_HIT(stfd); + case 55: PPC_DECODER_HIT(stfdu); + case 58: + switch ((ExtractBits(code, 30, 31) << 0)) { + case 0b00: PPC_DECODER_HIT(ld); + case 0b01: PPC_DECODER_HIT(ldu); + case 0b10: PPC_DECODER_HIT(lwa); + } + PPC_DECODER_MISS; + case 59: + switch ((ExtractBits(code, 26, 30) << 0)) { + case 0b10010: PPC_DECODER_HIT(fdivsx); + case 0b10100: PPC_DECODER_HIT(fsubsx); + case 0b10101: PPC_DECODER_HIT(faddsx); + case 0b10110: PPC_DECODER_HIT(fsqrtsx); + case 0b11000: PPC_DECODER_HIT(fresx); + case 0b11001: PPC_DECODER_HIT(fmulsx); + case 0b11100: PPC_DECODER_HIT(fmsubsx); + case 0b11101: PPC_DECODER_HIT(fmaddsx); + case 0b11110: PPC_DECODER_HIT(fnmsubsx); + case 0b11111: PPC_DECODER_HIT(fnmaddsx); + } + PPC_DECODER_MISS; + case 62: + switch ((ExtractBits(code, 30, 31) << 0)) { + case 0b00: PPC_DECODER_HIT(std); + case 0b01: PPC_DECODER_HIT(stdu); + } + PPC_DECODER_MISS; + case 63: + switch ((ExtractBits(code, 21, 30) << 0)) { + case 0b0000000000: PPC_DECODER_HIT(fcmpu); + case 0b0000001100: PPC_DECODER_HIT(frspx); + case 0b0000001110: PPC_DECODER_HIT(fctiwx); + case 0b0000001111: PPC_DECODER_HIT(fctiwzx); + case 0b0000100000: PPC_DECODER_HIT(fcmpo); + case 0b0000100110: PPC_DECODER_HIT(mtfsb1x); + case 0b0000101000: PPC_DECODER_HIT(fnegx); + case 0b0001000000: PPC_DECODER_HIT(mcrfs); + case 0b0001000110: PPC_DECODER_HIT(mtfsb0x); + case 0b0001001000: PPC_DECODER_HIT(fmrx); + case 0b0010000110: PPC_DECODER_HIT(mtfsfix); + case 0b0010001000: PPC_DECODER_HIT(fnabsx); + case 0b0100001000: PPC_DECODER_HIT(fabsx); + case 0b1001000111: PPC_DECODER_HIT(mffsx); + case 0b1011000111: PPC_DECODER_HIT(mtfsfx); + case 0b1100101110: PPC_DECODER_HIT(fctidx); + case 0b1100101111: PPC_DECODER_HIT(fctidzx); + case 0b1101001110: PPC_DECODER_HIT(fcfidx); + } + switch ((ExtractBits(code, 26, 30) << 0)) { + case 0b10010: PPC_DECODER_HIT(fdivx); + case 0b10100: PPC_DECODER_HIT(fsubx); + case 0b10101: PPC_DECODER_HIT(faddx); + case 0b10110: PPC_DECODER_HIT(fsqrtx); + case 0b10111: PPC_DECODER_HIT(fselx); + case 0b11001: PPC_DECODER_HIT(fmulx); + case 0b11010: PPC_DECODER_HIT(frsqrtex); + case 0b11100: PPC_DECODER_HIT(fmsubx); + case 0b11101: PPC_DECODER_HIT(fmaddx); + case 0b11110: PPC_DECODER_HIT(fnmsubx); + case 0b11111: PPC_DECODER_HIT(fnmaddx); + } + PPC_DECODER_MISS; + default: PPC_DECODER_MISS; + } +} + +} // namespace ppc +} // namespace cpu +} // namespace xe diff --git a/src/xenia/cpu/ppc/ppc_opcode_table.cc b/src/xenia/cpu/ppc/ppc_opcode_table.cc new file mode 100644 index 000000000..dcb5c47b7 --- /dev/null +++ b/src/xenia/cpu/ppc/ppc_opcode_table.cc @@ -0,0 +1,482 @@ +// This code was autogenerated by tools/ppc-table-gen.py. Do not modify! +// clang-format off +#include + +#include "xenia/cpu/ppc/ppc_opcode.h" +#include "xenia/cpu/ppc/ppc_opcode_info.h" + +namespace xe { +namespace cpu { +namespace ppc { + +#define INSTRUCTION(opcode, mnem, form, subform, group, desc) \ + {opcode, mnem, PPCOpcodeFormat::form, PPCOpcodeGroup::group, desc} +PPCOpcodeInfo ppc_opcode_table[] = { + INSTRUCTION(0x7c000014, "addcx" , kXO , D_A_B_OE_Rc , kInt, "Add Carrying" ), + INSTRUCTION(0x7c000114, "addex" , kXO , D_A_B_OE_Rc , kInt, "Add Extended" ), + INSTRUCTION(0x38000000, "addi" , kD , D_A_SIMM , kInt, "Add Immediate" ), + INSTRUCTION(0x30000000, "addic" , kD , D_A_SIMM , kInt, "Add Immediate Carrying" ), + INSTRUCTION(0x34000000, "addicx" , kD , D_A_SIMM , kInt, "Add Immediate Carrying and Record" ), + INSTRUCTION(0x3c000000, "addis" , kD , D_A_SIMM , kInt, "Add Immediate Shifted" ), + INSTRUCTION(0x7c0001d4, "addmex" , kXO , D_A_0_OE_Rc , kInt, "Add to Minus One Extended" ), + INSTRUCTION(0x7c000214, "addx" , kXO , D_A_B_OE_Rc , kInt, "Add" ), + INSTRUCTION(0x7c000194, "addzex" , kXO , D_A_0_OE_Rc , kInt, "Add to Zero Extended" ), + INSTRUCTION(0x7c000078, "andcx" , kX , S_A_B_Rc , kInt, "AND with Complement" ), + INSTRUCTION(0x74000000, "andisx" , kD , S_A_UIMM , kInt, "AND Immediate Shifted" ), + INSTRUCTION(0x70000000, "andix" , kD , S_A_UIMM , kInt, "AND Immediate" ), + INSTRUCTION(0x7c000038, "andx" , kX , S_A_B_Rc , kInt, "AND" ), + INSTRUCTION(0x4c000420, "bcctrx" , kXL , BO_BI_0_LK , kInt, "Branch Conditional to Count Register" ), + INSTRUCTION(0x4c000020, "bclrx" , kXL , BO_BI_0_LK , kInt, "Branch Conditional to Link Register" ), + INSTRUCTION(0x40000000, "bcx" , kB , BO_BI_BD_AA_LK , kInt, "Branch Conditional" ), + INSTRUCTION(0x48000000, "bx" , kI , LI_AA_LK , kInt, "Branch" ), + INSTRUCTION(0x7c000000, "cmp" , kX , crfD_L_A_B , kInt, "Compare" ), + INSTRUCTION(0x2c000000, "cmpi" , kD , crfD_L_A_SIMM , kInt, "Compare Immediate" ), + INSTRUCTION(0x7c000040, "cmpl" , kX , crfD_L_A_B , kInt, "Compare Logical" ), + INSTRUCTION(0x28000000, "cmpli" , kD , crfD_L_A_UIMM , kInt, "Compare Logical Immediate" ), + INSTRUCTION(0x7c000074, "cntlzdx" , kX , S_A_0_Rc , kInt, "Count Leading Zeros Doubleword" ), + INSTRUCTION(0x7c000034, "cntlzwx" , kX , S_A_0_Rc , kInt, "Count Leading Zeros Word" ), + INSTRUCTION(0x4c000202, "crand" , kXL , crbD_crbA_crbB , kInt, "Condition Register AND" ), + INSTRUCTION(0x4c000102, "crandc" , kXL , crbD_crbA_crbB , kInt, "Condition Register AND with Complement" ), + INSTRUCTION(0x4c000242, "creqv" , kXL , crbD_crbA_crbB , kInt, "Condition Register Equivalent" ), + INSTRUCTION(0x4c0001c2, "crnand" , kXL , crbD_crbA_crbB , kInt, "Condition Register NAND" ), + INSTRUCTION(0x4c000042, "crnor" , kXL , crbD_crbA_crbB , kInt, "Condition Register NOR" ), + INSTRUCTION(0x4c000382, "cror" , kXL , crbD_crbA_crbB , kInt, "Condition Register OR" ), + INSTRUCTION(0x4c000342, "crorc" , kXL , crbD_crbA_crbB , kInt, "Condition Register OR with Complement" ), + INSTRUCTION(0x4c000182, "crxor" , kXL , crbD_crbA_crbB , kInt, "Condition Register XOR" ), + INSTRUCTION(0x7c0005ec, "dcba" , kX , _0_A_B , kInt, "Data Cache Block Allocate" ), + INSTRUCTION(0x7c0000ac, "dcbf" , kX , _0_A_B , kInt, "Data Cache Block Flush" ), + INSTRUCTION(0x7c0003ac, "dcbi" , kX , _0_A_B , kInt, "Data Cache Block Invalidate" ), + INSTRUCTION(0x7c00006c, "dcbst" , kX , _0_A_B , kInt, "Data Cache Block Store" ), + INSTRUCTION(0x7c00022c, "dcbt" , kX , _0_A_B , kInt, "Data Cache Block Touch" ), + INSTRUCTION(0x7c0001ec, "dcbtst" , kX , _0_A_B , kInt, "Data Cache Block Touch for Store" ), + INSTRUCTION(0x7c0007ec, "dcbz" , kDCBZ , _0_A_B , kInt, "Data Cache Block Clear to Zero" ), + INSTRUCTION(0x7c2007ec, "dcbz128" , kDCBZ , _0_A_B , kInt, "Data Cache Block Clear to Zero 128" ), + INSTRUCTION(0x7c000392, "divdux" , kXO , D_A_B_OE_Rc , kInt, "Divide Doubleword Unsigned" ), + INSTRUCTION(0x7c0003d2, "divdx" , kXO , D_A_B_OE_Rc , kInt, "Divide Doubleword" ), + INSTRUCTION(0x7c000396, "divwux" , kXO , D_A_B_OE_Rc , kInt, "Divide Word Unsigned" ), + INSTRUCTION(0x7c0003d6, "divwx" , kXO , D_A_B_OE_Rc , kInt, "Divide Word" ), + INSTRUCTION(0x7c00026c, "eciwx" , kX , D_A_B , kInt, "External Control In Word Indexed" ), + INSTRUCTION(0x7c00036c, "ecowx" , kX , S_A_B , kInt, "External Control Out Word Indexed" ), + INSTRUCTION(0x7c0006ac, "eieio" , kX , _0_0_0 , kInt, "Enforce In-Order Execution of I/O" ), + INSTRUCTION(0x7c000238, "eqvx" , kX , S_A_B_Rc , kInt, "Equivalent" ), + INSTRUCTION(0x7c000774, "extsbx" , kX , S_A_0_Rc , kInt, "Extend Sign Byte" ), + INSTRUCTION(0x7c000734, "extshx" , kX , S_A_0_Rc , kInt, "Extend Sign Half Word" ), + INSTRUCTION(0x7c0007b4, "extswx" , kX , S_A_0_Rc , kInt, "Extend Sign Word" ), + INSTRUCTION(0xfc000210, "fabsx" , kX , D_0_B_Rc , kFp , "Floating Absolute Value" ), + INSTRUCTION(0xec00002a, "faddsx" , kA , D_A_B_0_Rc , kFp , "Floating Add Single" ), + INSTRUCTION(0xfc00002a, "faddx" , kA , D_A_B_0_Rc , kFp , "Floating Add" ), + INSTRUCTION(0xfc00069c, "fcfidx" , kX , D_A_B_Rc , kFp , "Floating Convert From Integer Doubleword" ), + INSTRUCTION(0xfc000040, "fcmpo" , kX , crfD_A_B , kFp , "Floating Compare Ordered" ), + INSTRUCTION(0xfc000000, "fcmpu" , kX , crfD_A_B , kFp , "Floating Compare Unordered" ), + INSTRUCTION(0xfc00065c, "fctidx" , kX , D_0_B_Rc , kFp , "Floating Convert to Integer Doubleword" ), + INSTRUCTION(0xfc00065e, "fctidzx" , kX , D_0_B_Rc , kFp , "Floating Convert to Integer Doubleword with Round Toward Zero" ), + INSTRUCTION(0xfc00001c, "fctiwx" , kX , D_0_B_Rc , kFp , "Floating Convert to Integer Word" ), + INSTRUCTION(0xfc00001e, "fctiwzx" , kX , D_0_B_Rc , kFp , "Floating Convert to Integer Word with Round Toward Zero" ), + INSTRUCTION(0xec000024, "fdivsx" , kA , D_A_B_0_Rc , kFp , "Floating Divide Single" ), + INSTRUCTION(0xfc000024, "fdivx" , kA , D_A_B_0_Rc , kFp , "Floating Divide" ), + INSTRUCTION(0xec00003a, "fmaddsx" , kA , D_A_B_C_Rc , kFp , "Floating Multiply-Add Single" ), + INSTRUCTION(0xfc00003a, "fmaddx" , kA , D_A_B_C_Rc , kFp , "Floating Multiply-Add" ), + INSTRUCTION(0xfc000090, "fmrx" , kX , D_0_B_Rc , kFp , "Floating Move Register" ), + INSTRUCTION(0xec000038, "fmsubsx" , kA , D_A_B_C_Rc , kFp , "Floating Multiply-Subtract Single" ), + INSTRUCTION(0xfc000038, "fmsubx" , kA , D_A_B_C_Rc , kFp , "Floating Multiply-Subtract" ), + INSTRUCTION(0xec000032, "fmulsx" , kA , D_A_0_C_Rc , kFp , "Floating Multiply Single" ), + INSTRUCTION(0xfc000032, "fmulx" , kA , D_A_0_C_Rc , kFp , "Floating Multiply" ), + INSTRUCTION(0xfc000110, "fnabsx" , kX , D_0_B_Rc , kFp , "Floating Negative Absolute Value" ), + INSTRUCTION(0xfc000050, "fnegx" , kX , D_0_B_Rc , kFp , "Floating Negate" ), + INSTRUCTION(0xec00003e, "fnmaddsx" , kA , D_A_B_C_Rc , kFp , "Floating Negative Multiply-Add Single" ), + INSTRUCTION(0xfc00003e, "fnmaddx" , kA , D_A_B_C_Rc , kFp , "Floating Negative Multiply-Add" ), + INSTRUCTION(0xec00003c, "fnmsubsx" , kA , D_A_B_C_Rc , kFp , "Floating Negative Multiply-Subtract Single" ), + INSTRUCTION(0xfc00003c, "fnmsubx" , kA , D_A_B_C_Rc , kFp , "Floating Negative Multiply-Subtract" ), + INSTRUCTION(0xec000030, "fresx" , kA , D_0_B_0_Rc , kFp , "Floating Reciprocal Estimate Single" ), + INSTRUCTION(0xfc000018, "frspx" , kX , D_0_B_Rc , kFp , "Floating Round to Single" ), + INSTRUCTION(0xfc000034, "frsqrtex" , kA , D_0_B_0_Rc , kFp , "Floating Reciprocal Square Root Estimate" ), + INSTRUCTION(0xfc00002e, "fselx" , kA , D_A_B_C_Rc , kFp , "Floating Select" ), + INSTRUCTION(0xec00002c, "fsqrtsx" , kA , D_0_B_0_Rc , kFp , "Floating Square Root Single" ), + INSTRUCTION(0xfc00002c, "fsqrtx" , kA , D_0_B_0_Rc , kFp , "Floating Square Root" ), + INSTRUCTION(0xec000028, "fsubsx" , kA , D_A_B_0_Rc , kFp , "Floating Subtract Single" ), + INSTRUCTION(0xfc000028, "fsubx" , kA , D_A_B_0_Rc , kFp , "Floating Subtract" ), + INSTRUCTION(0x7c0007ac, "icbi" , kX , _0_A_B , kInt, "Instruction Cache Block Invalidate" ), + INSTRUCTION(0x4c00012c, "isync" , kXL , _0_0_0 , kInt, "Instruction Synchronize" ), + INSTRUCTION(0x88000000, "lbz" , kD , D_A_d , kInt, "Load Byte and Zero" ), + INSTRUCTION(0x8c000000, "lbzu" , kD , D_A_d , kInt, "Load Byte and Zero with Update" ), + INSTRUCTION(0x7c0000ee, "lbzux" , kX , D_A_B , kInt, "Load Byte and Zero with Update Indexed" ), + INSTRUCTION(0x7c0000ae, "lbzx" , kX , D_A_B , kInt, "Load Byte and Zero Indexed" ), + INSTRUCTION(0xe8000000, "ld" , kDS , D_A_d , kInt, "Load Doubleword" ), + INSTRUCTION(0x7c0000a8, "ldarx" , kX , D_A_B , kInt, "Load Doubleword and Reserve Indexed" ), + INSTRUCTION(0x7c000428, "ldbrx" , kX , D_A_B , kInt, "Load Doubleword Byte-Reverse Indexed" ), + INSTRUCTION(0xe8000001, "ldu" , kDS , D_A_d , kInt, "Load Doubleword with Update" ), + INSTRUCTION(0x7c00006a, "ldux" , kX , D_A_B , kInt, "Load Doubleword with Update Indexed" ), + INSTRUCTION(0x7c00002a, "ldx" , kX , D_A_B , kInt, "Load Doubleword Indexed" ), + INSTRUCTION(0xc8000000, "lfd" , kD , D_A_d , kFp , "Load Floating-Point Double" ), + INSTRUCTION(0xcc000000, "lfdu" , kD , D_A_d , kFp , "Load Floating-Point Double with Update" ), + INSTRUCTION(0x7c0004ee, "lfdux" , kX , D_A_B , kFp , "Load Floating-Point Double with Update Indexed" ), + INSTRUCTION(0x7c0004ae, "lfdx" , kX , D_A_B , kFp , "Load Floating-Point Double Indexed" ), + INSTRUCTION(0xc0000000, "lfs" , kD , D_A_d , kFp , "Load Floating-Point Single" ), + INSTRUCTION(0xc4000000, "lfsu" , kD , D_A_d , kFp , "Load Floating-Point Single with Update" ), + INSTRUCTION(0x7c00046e, "lfsux" , kX , D_A_B , kFp , "Load Floating-Point Single with Update Indexed" ), + INSTRUCTION(0x7c00042e, "lfsx" , kX , D_A_B , kFp , "Load Floating-Point Single Indexed" ), + INSTRUCTION(0xa8000000, "lha" , kD , D_A_d , kInt, "Load Half Word Algebraic" ), + INSTRUCTION(0xac000000, "lhau" , kD , D_A_d , kInt, "Load Half Word Algebraic with Update" ), + INSTRUCTION(0x7c0002ee, "lhaux" , kX , D_A_B , kInt, "Load Half Word Algebraic with Update Indexed" ), + INSTRUCTION(0x7c0002ae, "lhax" , kX , D_A_B , kInt, "Load Half Word Algebraic Indexed" ), + INSTRUCTION(0x7c00062c, "lhbrx" , kX , D_A_B , kInt, "Load Half Word Byte-Reverse Indexed" ), + INSTRUCTION(0xa0000000, "lhz" , kD , D_A_d , kInt, "Load Half Word and Zero" ), + INSTRUCTION(0xa4000000, "lhzu" , kD , D_A_d , kInt, "Load Half Word and Zero with Update" ), + INSTRUCTION(0x7c00026e, "lhzux" , kX , D_A_B , kInt, "Load Half Word and Zero with Update Indexed" ), + INSTRUCTION(0x7c00022e, "lhzx" , kX , D_A_B , kInt, "Load Half Word and Zero Indexed" ), + INSTRUCTION(0xb8000000, "lmw" , kD , D_A_d , kInt, "Load Multiple Word" ), + INSTRUCTION(0x7c0004aa, "lswi" , kX , D_A_NB , kInt, "Load String Word Immediate" ), + INSTRUCTION(0x7c00042a, "lswx" , kX , D_A_B , kInt, "Load String Word Indexed" ), + INSTRUCTION(0x7c00000e, "lvebx" , kX , D_A_B , kVmx, "Load Vector Element Byte Indexed" ), + INSTRUCTION(0x7c00004e, "lvehx" , kX , D_A_B , kVmx, "Load Vector Element Half Word Indexed" ), + INSTRUCTION(0x7c00008e, "lvewx" , kX , D_A_B , kVmx, "Load Vector Element Word Indexed" ), + INSTRUCTION(0x10000083, "lvewx128" , kVX128_1, D_A_B , kVmx, "Load Vector Element Word Indexed 128" ), + INSTRUCTION(0x7c00040e, "lvlx" , kX , D_A_B , kVmx, "Load Vector Left Indexed" ), + INSTRUCTION(0x10000403, "lvlx128" , kVX128_1, D_A_B , kVmx, "Load Vector Left Indexed 128" ), + INSTRUCTION(0x7c00060e, "lvlxl" , kX , D_A_B , kVmx, "Load Vector Left Indexed LRU" ), + INSTRUCTION(0x10000603, "lvlxl128" , kVX128_1, D_A_B , kVmx, "Load Vector Left Indexed LRU 128" ), + INSTRUCTION(0x7c00044e, "lvrx" , kX , D_A_B , kVmx, "Load Vector Right Indexed" ), + INSTRUCTION(0x10000443, "lvrx128" , kVX128_1, D_A_B , kVmx, "Load Vector Right Indexed 128" ), + INSTRUCTION(0x7c00064e, "lvrxl" , kX , D_A_B , kVmx, "Load Vector Right Indexed LRU" ), + INSTRUCTION(0x10000643, "lvrxl128" , kVX128_1, D_A_B , kVmx, "Load Vector Right Indexed LRU 128" ), + INSTRUCTION(0x7c00000c, "lvsl" , kX , D_A_B , kVmx, "Load Vector for Shift Left Indexed" ), + INSTRUCTION(0x10000003, "lvsl128" , kVX128_1, D_A_B , kVmx, "Load Vector for Shift Left Indexed 128" ), + INSTRUCTION(0x7c00004c, "lvsr" , kX , D_A_B , kVmx, "Load Vector for Shift Right Indexed" ), + INSTRUCTION(0x10000043, "lvsr128" , kVX128_1, D_A_B , kVmx, "Load Vector for Shift Right Indexed 128" ), + INSTRUCTION(0x7c0000ce, "lvx" , kX , D_A_B , kVmx, "Load Vector Indexed" ), + INSTRUCTION(0x100000c3, "lvx128" , kVX128_1, D_A_B , kVmx, "Load Vector Indexed 128" ), + INSTRUCTION(0x7c0002ce, "lvxl" , kX , D_A_B , kVmx, "Load Vector Indexed LRU" ), + INSTRUCTION(0x100002c3, "lvxl128" , kVX128_1, D_A_B , kVmx, "Load Vector Indexed LRU 128" ), + INSTRUCTION(0xe8000002, "lwa" , kDS , D_A_d , kInt, "Load Word Algebraic" ), + INSTRUCTION(0x7c000028, "lwarx" , kX , D_A_B , kInt, "Load Word and Reserve Indexed" ), + INSTRUCTION(0x7c0002ea, "lwaux" , kX , D_A_B , kInt, "Load Word Algebraic with Update Indexed" ), + INSTRUCTION(0x7c0002aa, "lwax" , kX , D_A_B , kInt, "Load Word Algebraic Indexed" ), + INSTRUCTION(0x7c00042c, "lwbrx" , kX , D_A_B , kInt, "Load Word Byte-Reverse Indexed" ), + INSTRUCTION(0x80000000, "lwz" , kD , D_A_d , kInt, "Load Word and Zero" ), + INSTRUCTION(0x84000000, "lwzu" , kD , D_A_d , kInt, "Load Word and Zero with Update" ), + INSTRUCTION(0x7c00006e, "lwzux" , kX , D_A_B , kInt, "Load Word and Zero with Update Indexed" ), + INSTRUCTION(0x7c00002e, "lwzx" , kX , D_A_B , kInt, "Load Word and Zero Indexed" ), + INSTRUCTION(0x4c000000, "mcrf" , kXL , crfD_crfS_0 , kInt, "Move Condition Register Field" ), + INSTRUCTION(0xfc000080, "mcrfs" , kX , crfD_crfS_0 , kFp , "Move to Condition Register from FPSCR" ), + INSTRUCTION(0x7c000400, "mcrxr" , kX , crfD_0_0 , kInt, "Move to Condition Register from XER" ), + INSTRUCTION(0x7c000026, "mfcr" , kX , D_0_0 , kInt, "Move from Condition Register" ), + INSTRUCTION(0xfc00048e, "mffsx" , kX , D_0_0_Rc , kFp , "Move from FPSCR" ), + INSTRUCTION(0x7c0000a6, "mfmsr" , kX , D_0_0 , kInt, "Move from Machine State Register" ), + INSTRUCTION(0x7c0002a6, "mfspr" , kXFX , D_spr , kInt, "Move from Special-Purpose Register" ), + INSTRUCTION(0x7c0002e6, "mftb" , kXFX , D_tbr , kInt, "Move from Time Base" ), + INSTRUCTION(0x10000604, "mfvscr" , kVX , D_0_0 , kInt, "Move from VSCR" ), + INSTRUCTION(0x7c000120, "mtcrf" , kXFX , S_CRM , kInt, "Move to Condition Register Fields" ), + INSTRUCTION(0xfc00008c, "mtfsb0x" , kX , crbD_0_0_Rc , kFp , "Move to FPSCR Bit 0" ), + INSTRUCTION(0xfc00004c, "mtfsb1x" , kX , crbD_0_0_Rc , kFp , "Move to FPSCR Bit 1" ), + INSTRUCTION(0xfc00010c, "mtfsfix" , kX , crfD_0_IMM_Rc , kFp , "Move to FPSCR Field Immediate" ), + INSTRUCTION(0xfc00058e, "mtfsfx" , kXFL , FM_B_Rc , kFp , "Move to FPSCR Fields" ), + INSTRUCTION(0x7c000124, "mtmsr" , kX , S_0_0 , kInt, "Move to Machine State Register" ), + INSTRUCTION(0x7c000164, "mtmsrd" , kX , S_0_0 , kInt, "Move to Machine State Register Doubleword" ), + INSTRUCTION(0x7c0003a6, "mtspr" , kXFX , S_spr , kInt, "Move to Special-Purpose Register" ), + INSTRUCTION(0x10000644, "mtvscr" , kVX , S_0_0 , kInt, "Move to VSCR" ), + INSTRUCTION(0x7c000012, "mulhdux" , kXO , D_A_B_Rc , kInt, "Multiply High Doubleword Unsigned" ), + INSTRUCTION(0x7c000092, "mulhdx" , kXO , D_A_B_Rc , kInt, "Multiply High Doubleword" ), + INSTRUCTION(0x7c000016, "mulhwux" , kXO , D_A_B_Rc , kInt, "Multiply High Word Unsigned" ), + INSTRUCTION(0x7c000096, "mulhwx" , kXO , D_A_B_Rc , kInt, "Multiply High Word" ), + INSTRUCTION(0x7c0001d2, "mulldx" , kXO , D_A_B_OE_Rc , kInt, "Multiply Low Doubleword" ), + INSTRUCTION(0x1c000000, "mulli" , kD , D_A_SIMM , kInt, "Multiply Low Immediate" ), + INSTRUCTION(0x7c0001d6, "mullwx" , kXO , D_A_B_OE_Rc , kInt, "Multiply Low Word" ), + INSTRUCTION(0x7c0003b8, "nandx" , kX , S_A_B_Rc , kInt, "NAND" ), + INSTRUCTION(0x7c0000d0, "negx" , kXO , D_A_0_OE_Rc , kInt, "Negate" ), + INSTRUCTION(0x7c0000f8, "norx" , kX , S_A_B_Rc , kInt, "NOR" ), + INSTRUCTION(0x7c000338, "orcx" , kX , S_A_B_Rc , kInt, "OR with Complement" ), + INSTRUCTION(0x60000000, "ori" , kD , S_A_UIMM , kInt, "OR Immediate" ), + INSTRUCTION(0x64000000, "oris" , kD , S_A_UIMM , kInt, "OR Immediate Shifted" ), + INSTRUCTION(0x7c000378, "orx" , kX , S_A_B_Rc , kInt, "OR" ), + INSTRUCTION(0x78000010, "rldclx" , kMDS , S_A_B_MB_ME_Rc , kInt, "Rotate Left Doubleword then Clear Left" ), + INSTRUCTION(0x78000012, "rldcrx" , kMDS , S_A_B_MB_ME_Rc , kInt, "Rotate Left Doubleword then Clear Right" ), + INSTRUCTION(0x78000000, "rldiclx" , kMDSH , S_A_SH_MB_ME_Rc, kInt, "Rotate Left Doubleword Immediate then Clear Left" ), + INSTRUCTION(0x78000004, "rldicrx" , kMDSH , S_A_SH_MB_ME_Rc, kInt, "Rotate Left Doubleword Immediate then Clear Right" ), + INSTRUCTION(0x78000008, "rldicx" , kMDSH , S_A_SH_MB_ME_Rc, kInt, "Rotate Left Doubleword Immediate then Clear" ), + INSTRUCTION(0x7800000c, "rldimix" , kMDSH , S_A_SH_MB_ME_Rc, kInt, "Rotate Left Doubleword Immediate then Mask Insert" ), + INSTRUCTION(0x50000000, "rlwimix" , kM , S_A_SH_MB_ME_Rc, kInt, "Rotate Left Word Immediate then Mask Insert" ), + INSTRUCTION(0x54000000, "rlwinmx" , kM , S_A_SH_MB_ME_Rc, kInt, "Rotate Left Word Immediate then AND with Mask" ), + INSTRUCTION(0x5c000000, "rlwnmx" , kM , S_A_SH_MB_ME_Rc, kInt, "Rotate Left Word then AND with Mask" ), + INSTRUCTION(0x44000002, "sc" , kSC , sc , kInt, "System Call" ), + INSTRUCTION(0x7c000036, "sldx" , kX , S_A_B_Rc , kInt, "Shift Left Doubleword" ), + INSTRUCTION(0x7c000030, "slwx" , kX , S_A_B_Rc , kInt, "Shift Left Word" ), + INSTRUCTION(0x7c000674, "sradix" , kXS , S_A_SH_Rc , kInt, "Shift Right Algebraic Doubleword Immediate" ), + INSTRUCTION(0x7c000634, "sradx" , kX , S_A_B_Rc , kInt, "Shift Right Algebraic Doubleword" ), + INSTRUCTION(0x7c000670, "srawix" , kX , S_A_SH_Rc , kInt, "Shift Right Algebraic Word Immediate" ), + INSTRUCTION(0x7c000630, "srawx" , kX , S_A_B_Rc , kInt, "Shift Right Algebraic Word" ), + INSTRUCTION(0x7c000436, "srdx" , kX , S_A_B_Rc , kInt, "Shift Right Doubleword" ), + INSTRUCTION(0x7c000430, "srwx" , kX , S_A_B_Rc , kInt, "Shift Right Word" ), + INSTRUCTION(0x98000000, "stb" , kD , S_A_d , kInt, "Store Byte" ), + INSTRUCTION(0x9c000000, "stbu" , kD , S_A_d , kInt, "Store Byte with Update" ), + INSTRUCTION(0x7c0001ee, "stbux" , kX , S_A_B , kInt, "Store Byte with Update Indexed" ), + INSTRUCTION(0x7c0001ae, "stbx" , kX , S_A_B , kInt, "Store Byte Indexed" ), + INSTRUCTION(0xf8000000, "std" , kDS , S_A_d , kInt, "Store Doubleword" ), + INSTRUCTION(0x7c000528, "stdbrx" , kX , S_A_B , kInt, "Store Doubleword Byte-Reverse Indexed" ), + INSTRUCTION(0x7c0001ad, "stdcx" , kX , S_A_B_1 , kInt, "Store Doubleword Conditional Indexed" ), + INSTRUCTION(0xf8000001, "stdu" , kDS , S_A_d , kInt, "Store Doubleword with Update" ), + INSTRUCTION(0x7c00016a, "stdux" , kX , S_A_B , kInt, "Store Doubleword with Update Indexed" ), + INSTRUCTION(0x7c00012a, "stdx" , kX , S_A_B , kInt, "Store Doubleword Indexed" ), + INSTRUCTION(0xd8000000, "stfd" , kD , S_A_d , kFp , "Store Floating-Point Double" ), + INSTRUCTION(0xdc000000, "stfdu" , kD , S_A_d , kFp , "Store Floating-Point Double with Update" ), + INSTRUCTION(0x7c0005ee, "stfdux" , kX , S_A_B , kFp , "Store Floating-Point Double with Update Indexed" ), + INSTRUCTION(0x7c0005ae, "stfdx" , kX , S_A_B , kFp , "Store Floating-Point Double Indexed" ), + INSTRUCTION(0x7c0007ae, "stfiwx" , kX , S_A_B , kFp , "Store Floating-Point as Integer Word Indexed" ), + INSTRUCTION(0xd0000000, "stfs" , kD , S_A_d , kFp , "Store Floating-Point Single" ), + INSTRUCTION(0xd4000000, "stfsu" , kD , S_A_d , kFp , "Store Floating-Point Single with Update" ), + INSTRUCTION(0x7c00056e, "stfsux" , kX , S_A_B , kFp , "Store Floating-Point Single with Update Indexed" ), + INSTRUCTION(0x7c00052e, "stfsx" , kX , S_A_B , kFp , "Store Floating-Point Single Indexed" ), + INSTRUCTION(0xb0000000, "sth" , kD , S_A_d , kInt, "Store Half Word" ), + INSTRUCTION(0x7c00072c, "sthbrx" , kX , S_A_B , kInt, "Store Half Word Byte-Reverse Indexed" ), + INSTRUCTION(0xb4000000, "sthu" , kD , S_A_d , kInt, "Store Half Word with Update" ), + INSTRUCTION(0x7c00036e, "sthux" , kX , S_A_B , kInt, "Store Half Word with Update Indexed" ), + INSTRUCTION(0x7c00032e, "sthx" , kX , S_A_B , kInt, "Store Half Word Indexed" ), + INSTRUCTION(0xbc000000, "stmw" , kD , S_A_d , kInt, "Store Multiple Word" ), + INSTRUCTION(0x7c0005aa, "stswi" , kX , S_A_NB , kInt, "Store String Word Immediate" ), + INSTRUCTION(0x7c00052a, "stswx" , kX , S_A_B , kInt, "Store String Word Indexed" ), + INSTRUCTION(0x7c00010e, "stvebx" , kX , S_A_B , kVmx, "Store Vector Element Byte Indexed" ), + INSTRUCTION(0x7c00014e, "stvehx" , kX , S_A_B , kVmx, "Store Vector Element Half Word Indexed" ), + INSTRUCTION(0x7c00018e, "stvewx" , kX , S_A_B , kVmx, "Store Vector Element Word Indexed" ), + INSTRUCTION(0x10000183, "stvewx128" , kVX128_1, S_A_B , kVmx, "Store Vector Element Word Indexed 128" ), + INSTRUCTION(0x7c00050e, "stvlx" , kX , S_A_B , kVmx, "Store Vector Left Indexed" ), + INSTRUCTION(0x10000503, "stvlx128" , kVX128_1, S_A_B , kVmx, "Store Vector Left Indexed 128" ), + INSTRUCTION(0x7c00070e, "stvlxl" , kX , S_A_B , kVmx, "Store Vector Left Indexed LRU" ), + INSTRUCTION(0x10000703, "stvlxl128" , kVX128_1, S_A_B , kVmx, "Store Vector Left Indexed LRU 128" ), + INSTRUCTION(0x7c00054e, "stvrx" , kX , S_A_B , kVmx, "Store Vector Right Indexed" ), + INSTRUCTION(0x10000543, "stvrx128" , kVX128_1, S_A_B , kVmx, "Store Vector Right Indexed 128" ), + INSTRUCTION(0x7c00074e, "stvrxl" , kX , S_A_B , kVmx, "Store Vector Right Indexed LRU" ), + INSTRUCTION(0x10000743, "stvrxl128" , kVX128_1, S_A_B , kVmx, "Store Vector Right Indexed LRU 128" ), + INSTRUCTION(0x7c0001ce, "stvx" , kX , S_A_B , kVmx, "Store Vector Indexed" ), + INSTRUCTION(0x100001c3, "stvx128" , kVX128_1, S_A_B , kVmx, "Store Vector Indexed 128" ), + INSTRUCTION(0x7c0003ce, "stvxl" , kX , S_A_B , kVmx, "Store Vector Indexed LRU" ), + INSTRUCTION(0x100003c3, "stvxl128" , kVX128_1, S_A_B , kVmx, "Store Vector Indexed LRU 128" ), + INSTRUCTION(0x90000000, "stw" , kD , S_A_d , kInt, "Store Word" ), + INSTRUCTION(0x7c00052c, "stwbrx" , kX , S_A_B , kInt, "Store Word Byte-Reverse Indexed" ), + INSTRUCTION(0x7c00012d, "stwcx" , kX , S_A_B_1 , kInt, "Store Word Conditional Indexed" ), + INSTRUCTION(0x94000000, "stwu" , kD , S_A_d , kInt, "Store Word with Update" ), + INSTRUCTION(0x7c00016e, "stwux" , kX , S_A_B , kInt, "Store Word with Update Indexed" ), + INSTRUCTION(0x7c00012e, "stwx" , kX , S_A_B , kInt, "Store Word Indexed" ), + INSTRUCTION(0x7c000010, "subfcx" , kXO , D_A_B_OE_Rc , kInt, "Subtract From Carrying" ), + INSTRUCTION(0x7c000110, "subfex" , kXO , D_A_B_OE_Rc , kInt, "Subtract From Extended" ), + INSTRUCTION(0x20000000, "subficx" , kD , D_A_SIMM , kInt, "Subtract From Immediate Carrying" ), + INSTRUCTION(0x7c0001d0, "subfmex" , kXO , D_A_0_OE_Rc , kInt, "Subtract From Minus One Extended" ), + INSTRUCTION(0x7c000050, "subfx" , kXO , D_A_B_OE_Rc , kInt, "Subtract From" ), + INSTRUCTION(0x7c000190, "subfzex" , kXO , D_A_0_OE_Rc , kInt, "Subtract From Zero Extended" ), + INSTRUCTION(0x7c0004ac, "sync" , kX , _0_0_0 , kInt, "Synchronize" ), + INSTRUCTION(0x7c000088, "td" , kX , TO_A_B , kInt, "Trap Doubleword" ), + INSTRUCTION(0x08000000, "tdi" , kD , TO_A_SIMM , kInt, "Trap Doubleword Immediate" ), + INSTRUCTION(0x7c000008, "tw" , kX , TO_A_B , kInt, "Trap Word" ), + INSTRUCTION(0x0c000000, "twi" , kD , TO_A_SIMM , kInt, "Trap Word Immediate" ), + INSTRUCTION(0x10000180, "vaddcuw" , kVX , D_A_B , kVmx, "Vector Add Carryout Unsigned Word" ), + INSTRUCTION(0x1000000a, "vaddfp" , kVX , D_A_B , kVmx, "Vector Add Floating Point" ), + INSTRUCTION(0x14000010, "vaddfp128" , kVX128 , D_A_B , kVmx, "Vector128 Add Floating Point" ), + INSTRUCTION(0x10000300, "vaddsbs" , kVX , D_A_B , kVmx, "Vector Add Signed Byte Saturate" ), + INSTRUCTION(0x10000340, "vaddshs" , kVX , D_A_B , kVmx, "Vector Add Signed Half Word Saturate" ), + INSTRUCTION(0x10000380, "vaddsws" , kVX , D_A_B , kVmx, "Vector Add Signed Word Saturate" ), + INSTRUCTION(0x10000000, "vaddubm" , kVX , D_A_B , kVmx, "Vector Add Unsigned Byte Modulo" ), + INSTRUCTION(0x10000200, "vaddubs" , kVX , D_A_B , kVmx, "Vector Add Unsigned Byte Saturate" ), + INSTRUCTION(0x10000040, "vadduhm" , kVX , D_A_B , kVmx, "Vector Add Unsigned Half Word Modulo" ), + INSTRUCTION(0x10000240, "vadduhs" , kVX , D_A_B , kVmx, "Vector Add Unsigned Half Word Saturate" ), + INSTRUCTION(0x10000080, "vadduwm" , kVX , D_A_B , kVmx, "Vector Add Unsigned Word Modulo" ), + INSTRUCTION(0x10000280, "vadduws" , kVX , D_A_B , kVmx, "Vector Add Unsigned Word Saturate" ), + INSTRUCTION(0x10000404, "vand" , kVX , D_A_B , kVmx, "Vector Logical AND" ), + INSTRUCTION(0x14000210, "vand128" , kVX128 , D_A_B , kVmx, "Vector128 Logical AND" ), + INSTRUCTION(0x10000444, "vandc" , kVX , D_A_B , kVmx, "Vector Logical AND with Complement" ), + INSTRUCTION(0x14000250, "vandc128" , kVX128 , D_A_B , kVmx, "Vector128 Logical AND with Complement" ), + INSTRUCTION(0x10000502, "vavgsb" , kVX , D_A_B , kVmx, "Vector Average Signed Byte" ), + INSTRUCTION(0x10000542, "vavgsh" , kVX , D_A_B , kVmx, "Vector Average Signed Half Word" ), + INSTRUCTION(0x10000582, "vavgsw" , kVX , D_A_B , kVmx, "Vector Average Signed Word" ), + INSTRUCTION(0x10000402, "vavgub" , kVX , D_A_B , kVmx, "Vector Average Unsigned Byte" ), + INSTRUCTION(0x10000442, "vavguh" , kVX , D_A_B , kVmx, "Vector Average Unsigned Half Word" ), + INSTRUCTION(0x10000482, "vavguw" , kVX , D_A_B , kVmx, "Vector Average Unsigned Word" ), + INSTRUCTION(0x18000230, "vcfpsxws128" , kVX128_3, D_B_SIMM , kVmx, "Vector128 Convert From Floating-Point to Signed Fixed-Point Word Saturate" ), + INSTRUCTION(0x18000270, "vcfpuxws128" , kVX128_3, D_B_UIMM , kVmx, "Vector128 Convert From Floating-Point to Unsigned Fixed-Point Word Saturate"), + INSTRUCTION(0x1000034a, "vcfsx" , kVX , D_A_B , kVmx, "Vector Convert from Signed Fixed-Point Word" ), + INSTRUCTION(0x1000030a, "vcfux" , kVX , D_A_B , kVmx, "Vector Convert from Unsigned Fixed-Point Word" ), + INSTRUCTION(0x100003c6, "vcmpbfp" , kVC , D_A_B , kVmx, "Vector Compare Bounds Floating Point" ), + INSTRUCTION(0x18000180, "vcmpbfp128" , kVX128_R, D_A_B , kVmx, "Vector128 Compare Bounds Floating Point" ), + INSTRUCTION(0x100000c6, "vcmpeqfp" , kVC , D_A_B , kVmx, "Vector Compare Equal-to Floating Point" ), + INSTRUCTION(0x18000000, "vcmpeqfp128" , kVX128_R, D_A_B , kVmx, "Vector128 Compare Equal-to Floating Point" ), + INSTRUCTION(0x10000006, "vcmpequb" , kVC , D_A_B , kVmx, "Vector Compare Equal-to Unsigned Byte" ), + INSTRUCTION(0x10000046, "vcmpequh" , kVC , D_A_B , kVmx, "Vector Compare Equal-to Unsigned Half Word" ), + INSTRUCTION(0x10000086, "vcmpequw" , kVC , D_A_B , kVmx, "Vector Compare Equal-to Unsigned Word" ), + INSTRUCTION(0x18000200, "vcmpequw128" , kVX128_R, D_A_B , kVmx, "Vector128 Compare Equal-to Unsigned Word" ), + INSTRUCTION(0x100001c6, "vcmpgefp" , kVC , D_A_B , kVmx, "Vector Compare Greater-Than-or-Equal-to Floating Point" ), + INSTRUCTION(0x18000080, "vcmpgefp128" , kVX128_R, D_A_B , kVmx, "Vector128 Compare Greater-Than-or-Equal-to Floating Point" ), + INSTRUCTION(0x100002c6, "vcmpgtfp" , kVC , D_A_B , kVmx, "Vector Compare Greater-Than Floating Point" ), + INSTRUCTION(0x18000100, "vcmpgtfp128" , kVX128_R, D_A_B , kVmx, "Vector128 Compare Greater-Than Floating-Point" ), + INSTRUCTION(0x10000306, "vcmpgtsb" , kVC , D_A_B , kVmx, "Vector Compare Greater-Than Signed Byte" ), + INSTRUCTION(0x10000346, "vcmpgtsh" , kVC , D_A_B , kVmx, "Vector Compare Greater-Than Signed Half Word" ), + INSTRUCTION(0x10000386, "vcmpgtsw" , kVC , D_A_B , kVmx, "Vector Compare Greater-Than Signed Word" ), + INSTRUCTION(0x10000206, "vcmpgtub" , kVC , D_A_B , kVmx, "Vector Compare Greater-Than Unsigned Byte" ), + INSTRUCTION(0x10000246, "vcmpgtuh" , kVC , D_A_B , kVmx, "Vector Compare Greater-Than Unsigned Half Word" ), + INSTRUCTION(0x10000286, "vcmpgtuw" , kVC , D_A_B , kVmx, "Vector Compare Greater-Than Unsigned Word" ), + INSTRUCTION(0x180002b0, "vcsxwfp128" , kVX128_3, D_B_SIMM , kVmx, "Vector128 Convert From Signed Fixed-Point Word to Floating-Point" ), + INSTRUCTION(0x100003ca, "vctsxs" , kVX , D_A_B , kVmx, "Vector Convert to Signed Fixed-Point Word Saturate" ), + INSTRUCTION(0x1000038a, "vctuxs" , kVX , D_A_B , kVmx, "Vector Convert to Unsigned Fixed-Point Word Saturate" ), + INSTRUCTION(0x180002f0, "vcuxwfp128" , kVX128_3, D_B_SIMM , kVmx, "Vector128 Convert From Unsigned Fixed-Point Word to Floating-Point" ), + INSTRUCTION(0x1000018a, "vexptefp" , kVX , D_A_B , kVmx, "Vector 2 Raised to the Exponent Estimate Floating Point" ), + INSTRUCTION(0x180006b0, "vexptefp128" , kVX128_3, D_B , kVmx, "Vector128 Log2 Estimate Floating Point" ), + INSTRUCTION(0x100001ca, "vlogefp" , kVX , D_A_B , kVmx, "Vector Log2 Estimate Floating Point" ), + INSTRUCTION(0x180006f0, "vlogefp128" , kVX128_3, D_B , kVmx, "Vector128 Log2 Estimate Floating Point" ), + INSTRUCTION(0x14000110, "vmaddcfp128" , kVX128 , D_A_D_B , kVmx, "Vector128 Multiply Add Floating Point" ), + INSTRUCTION(0x1000002e, "vmaddfp" , kVA , D_A_B_C , kVmx, "Vector Multiply-Add Floating Point" ), + INSTRUCTION(0x140000d0, "vmaddfp128" , kVX128 , D_A_D_B , kVmx, "Vector128 Multiply Add Floating Point" ), + INSTRUCTION(0x1000040a, "vmaxfp" , kVX , D_A_B , kVmx, "Vector Maximum Floating Point" ), + INSTRUCTION(0x18000280, "vmaxfp128" , kVX128 , D_A_B , kVmx, "Vector128 Maximum Floating Point" ), + INSTRUCTION(0x10000102, "vmaxsb" , kVX , D_A_B , kVmx, "Vector Maximum Signed Byte" ), + INSTRUCTION(0x10000142, "vmaxsh" , kVX , D_A_B , kVmx, "Vector Maximum Signed Half Word" ), + INSTRUCTION(0x10000182, "vmaxsw" , kVX , D_A_B , kVmx, "Vector Maximum Signed Word" ), + INSTRUCTION(0x10000002, "vmaxub" , kVX , D_A_B , kVmx, "Vector Maximum Unsigned Byte" ), + INSTRUCTION(0x10000042, "vmaxuh" , kVX , D_A_B , kVmx, "Vector Maximum Unsigned Half Word" ), + INSTRUCTION(0x10000082, "vmaxuw" , kVX , D_A_B , kVmx, "Vector Maximum Unsigned Word" ), + INSTRUCTION(0x10000020, "vmhaddshs" , kVA , D_A_B_C , kVmx, "Vector Multiply-High and Add Signed Signed Half Word Saturate" ), + INSTRUCTION(0x10000021, "vmhraddshs" , kVA , D_A_B_C , kVmx, "Vector Multiply-High Round and Add Signed Signed Half Word Saturate" ), + INSTRUCTION(0x1000044a, "vminfp" , kVX , D_A_B , kVmx, "Vector Minimum Floating Point" ), + INSTRUCTION(0x180002c0, "vminfp128" , kVX128 , D_A_B , kVmx, "Vector128 Minimum Floating Point" ), + INSTRUCTION(0x10000302, "vminsb" , kVX , D_A_B , kVmx, "Vector Minimum Signed Byte" ), + INSTRUCTION(0x10000342, "vminsh" , kVX , D_A_B , kVmx, "Vector Minimum Signed Half Word" ), + INSTRUCTION(0x10000382, "vminsw" , kVX , D_A_B , kVmx, "Vector Minimum Signed Word" ), + INSTRUCTION(0x10000202, "vminub" , kVX , D_A_B , kVmx, "Vector Minimum Unsigned Byte" ), + INSTRUCTION(0x10000242, "vminuh" , kVX , D_A_B , kVmx, "Vector Minimum Unsigned Half Word" ), + INSTRUCTION(0x10000282, "vminuw" , kVX , D_A_B , kVmx, "Vector Minimum Unsigned Word" ), + INSTRUCTION(0x10000022, "vmladduhm" , kVA , D_A_B_C , kVmx, "Vector Multiply-Low and Add Unsigned Half Word Modulo" ), + INSTRUCTION(0x1000000c, "vmrghb" , kVX , D_A_B , kVmx, "Vector Merge High Byte" ), + INSTRUCTION(0x1000004c, "vmrghh" , kVX , D_A_B , kVmx, "Vector Merge High Half Word" ), + INSTRUCTION(0x1000008c, "vmrghw" , kVX , D_A_B , kVmx, "Vector Merge High Word" ), + INSTRUCTION(0x18000300, "vmrghw128" , kVX128 , D_A_B , kVmx, "Vector128 Merge High Word" ), + INSTRUCTION(0x1000010c, "vmrglb" , kVX , D_A_B , kVmx, "Vector Merge Low Byte" ), + INSTRUCTION(0x1000014c, "vmrglh" , kVX , D_A_B , kVmx, "Vector Merge Low Half Word" ), + INSTRUCTION(0x1000018c, "vmrglw" , kVX , D_A_B , kVmx, "Vector Merge Low Word" ), + INSTRUCTION(0x18000340, "vmrglw128" , kVX128 , D_A_B , kVmx, "Vector128 Merge Low Word" ), + INSTRUCTION(0x14000190, "vmsum3fp128" , kVX128 , D_A_B , kVmx, "Vector128 Multiply Sum 3-way Floating Point" ), + INSTRUCTION(0x140001d0, "vmsum4fp128" , kVX128 , D_A_B , kVmx, "Vector128 Multiply Sum 4-way Floating-Point" ), + INSTRUCTION(0x10000025, "vmsummbm" , kVA , D_A_B_C , kVmx, "Vector Multiply-Sum Mixed-Sign Byte Modulo" ), + INSTRUCTION(0x10000028, "vmsumshm" , kVA , D_A_B_C , kVmx, "Vector Multiply-Sum Signed Half Word Modulo" ), + INSTRUCTION(0x10000029, "vmsumshs" , kVA , D_A_B_C , kVmx, "Vector Multiply-Sum Signed Half Word Saturate" ), + INSTRUCTION(0x10000024, "vmsumubm" , kVA , D_A_B_C , kVmx, "Vector Multiply-Sum Unsigned Byte Modulo" ), + INSTRUCTION(0x10000026, "vmsumuhm" , kVA , D_A_B_C , kVmx, "Vector Multiply-Sum Unsigned Half Word Modulo" ), + INSTRUCTION(0x10000027, "vmsumuhs" , kVA , D_A_B_C , kVmx, "Vector Multiply-Sum Unsigned Half Word Saturate" ), + INSTRUCTION(0x10000308, "vmulesb" , kVX , D_A_B , kVmx, "Vector Multiply Even Signed Byte" ), + INSTRUCTION(0x10000348, "vmulesh" , kVX , D_A_B , kVmx, "Vector Multiply Even Signed Half Word" ), + INSTRUCTION(0x10000208, "vmuleub" , kVX , D_A_B , kVmx, "Vector Multiply Even Unsigned Byte" ), + INSTRUCTION(0x10000248, "vmuleuh" , kVX , D_A_B , kVmx, "Vector Multiply Even Unsigned Half Word" ), + INSTRUCTION(0x14000090, "vmulfp128" , kVX128 , D_A_B , kVmx, "Vector128 Multiply Floating-Point" ), + INSTRUCTION(0x10000108, "vmulosb" , kVX , D_A_B , kVmx, "Vector Multiply Odd Signed Byte" ), + INSTRUCTION(0x10000148, "vmulosh" , kVX , D_A_B , kVmx, "Vector Multiply Odd Signed Half Word" ), + INSTRUCTION(0x10000008, "vmuloub" , kVX , D_A_B , kVmx, "Vector Multiply Odd Unsigned Byte" ), + INSTRUCTION(0x10000048, "vmulouh" , kVX , D_A_B , kVmx, "Vector Multiply Odd Unsigned Half Word" ), + INSTRUCTION(0x1000002f, "vnmsubfp" , kVA , D_A_B_C , kVmx, "Vector Negative Multiply-Subtract Floating Point" ), + INSTRUCTION(0x14000150, "vnmsubfp128" , kVX128 , D_A_B , kVmx, "Vector128 Negative Multiply-Subtract Floating Point" ), + INSTRUCTION(0x10000504, "vnor" , kVX , D_A_B , kVmx, "Vector Logical NOR" ), + INSTRUCTION(0x14000290, "vnor128" , kVX128 , D_A_B , kVmx, "Vector128 Logical NOR" ), + INSTRUCTION(0x10000484, "vor" , kVX , D_A_B , kVmx, "Vector Logical OR" ), + INSTRUCTION(0x140002d0, "vor128" , kVX128 , D_A_B , kVmx, "Vector128 Logical OR" ), + INSTRUCTION(0x1000002b, "vperm" , kVA , D_A_B_C , kVmx, "Vector Permute" ), + INSTRUCTION(0x14000000, "vperm128" , kVX128_2, D_A_B_C , kVmx, "Vector128 Permute" ), + INSTRUCTION(0x18000210, "vpermwi128" , kVX128_P, D_A_B_C , kVmx, "Vector128 Permutate Word Immediate" ), + INSTRUCTION(0x18000610, "vpkd3d128" , kVX128_4, D_B , kVmx, "Vector128 Pack D3Dtype, Rotate Left Immediate and Mask Insert" ), + INSTRUCTION(0x1000030e, "vpkpx" , kVX , D_A_B , kVmx, "Vector Pack Pixel" ), + INSTRUCTION(0x1000018e, "vpkshss" , kVX , D_A_B , kVmx, "Vector Pack Signed Half Word Signed Saturate" ), + INSTRUCTION(0x14000200, "vpkshss128" , kVX128 , D_A_B , kVmx, "Vector128 Pack Signed Half Word Signed Saturate" ), + INSTRUCTION(0x1000010e, "vpkshus" , kVX , D_A_B , kVmx, "Vector Pack Signed Half Word Unsigned Saturate" ), + INSTRUCTION(0x14000240, "vpkshus128" , kVX128 , D_A_B , kVmx, "Vector128 Pack Signed Half Word Unsigned Saturate" ), + INSTRUCTION(0x100001ce, "vpkswss" , kVX , D_A_B , kVmx, "Vector Pack Signed Word Signed Saturate" ), + INSTRUCTION(0x14000280, "vpkswss128" , kVX128 , D_A_B , kVmx, "Vector128 Pack Signed Word Signed Saturate" ), + INSTRUCTION(0x1000014e, "vpkswus" , kVX , D_A_B , kVmx, "Vector Pack Signed Word Unsigned Saturate" ), + INSTRUCTION(0x140002c0, "vpkswus128" , kVX128 , D_A_B , kVmx, "Vector128 Pack Signed Word Unsigned Saturate" ), + INSTRUCTION(0x1000000e, "vpkuhum" , kVX , D_A_B , kVmx, "Vector Pack Unsigned Half Word Unsigned Modulo" ), + INSTRUCTION(0x14000300, "vpkuhum128" , kVX128 , D_A_B , kVmx, "Vector128 Pack Unsigned Half Word Unsigned Modulo" ), + INSTRUCTION(0x1000008e, "vpkuhus" , kVX , D_A_B , kVmx, "Vector Pack Unsigned Half Word Unsigned Saturate" ), + INSTRUCTION(0x14000340, "vpkuhus128" , kVX128 , D_A_B , kVmx, "Vector128 Pack Unsigned Half Word Unsigned Saturate" ), + INSTRUCTION(0x1000004e, "vpkuwum" , kVX , D_A_B , kVmx, "Vector Pack Unsigned Word Unsigned Modulo" ), + INSTRUCTION(0x14000380, "vpkuwum128" , kVX128 , D_A_B , kVmx, "Vector128 Pack Unsigned Word Unsigned Modulo" ), + INSTRUCTION(0x100000ce, "vpkuwus" , kVX , D_A_B , kVmx, "Vector Pack Unsigned Word Unsigned Saturate" ), + INSTRUCTION(0x140003c0, "vpkuwus128" , kVX128 , D_A_B , kVmx, "Vector128 Pack Unsigned Word Unsigned Saturate" ), + INSTRUCTION(0x1000010a, "vrefp" , kVX , D_A_B , kVmx, "Vector Reciprocal Estimate Floating Point" ), + INSTRUCTION(0x18000630, "vrefp128" , kVX128_3, D_B , kVmx, "Vector128 Reciprocal Estimate Floating Point" ), + INSTRUCTION(0x100002ca, "vrfim" , kVX , D_A_B , kVmx, "Vector Round to Floating-Point Integer toward -Infinity" ), + INSTRUCTION(0x18000330, "vrfim128" , kVX128_3, D_B , kVmx, "Vector128 Round to Floating-Point Integer toward -Infinity" ), + INSTRUCTION(0x1000020a, "vrfin" , kVX , D_A_B , kVmx, "Vector Round to Floating-Point Integer Nearest" ), + INSTRUCTION(0x18000370, "vrfin128" , kVX128_3, D_B , kVmx, "Vector128 Round to Floating-Point Integer Nearest" ), + INSTRUCTION(0x1000028a, "vrfip" , kVX , D_A_B , kVmx, "Vector Round to Floating-Point Integer toward +Infinity" ), + INSTRUCTION(0x180003b0, "vrfip128" , kVX128_3, D_B , kVmx, "Vector128 Round to Floating-Point Integer toward +Infinity" ), + INSTRUCTION(0x1000024a, "vrfiz" , kVX , D_A_B , kVmx, "Vector Round to Floating-Point Integer toward Zero" ), + INSTRUCTION(0x180003f0, "vrfiz128" , kVX128_3, D_B , kVmx, "Vector128 Round to Floating-Point Integer toward Zero" ), + INSTRUCTION(0x10000004, "vrlb" , kVX , D_A_B , kVmx, "Vector Rotate Left Integer Byte" ), + INSTRUCTION(0x10000044, "vrlh" , kVX , D_A_B , kVmx, "Vector Rotate Left Integer Half Word" ), + INSTRUCTION(0x18000710, "vrlimi128" , kVX128_4, D_B_UIMM , kVmx, "Vector128 Rotate Left Immediate and Mask Insert" ), + INSTRUCTION(0x10000084, "vrlw" , kVX , D_A_B , kVmx, "Vector Rotate Left Integer Word" ), + INSTRUCTION(0x18000050, "vrlw128" , kVX128 , D_A_B , kVmx, "Vector128 Rotate Left Word" ), + INSTRUCTION(0x1000014a, "vrsqrtefp" , kVX , D_A_B , kVmx, "Vector Reciprocal Square Root Estimate Floating Point" ), + INSTRUCTION(0x18000670, "vrsqrtefp128", kVX128_3, D_B , kVmx, "Vector128 Reciprocal Square Root Estimate Floating Point" ), + INSTRUCTION(0x1000002a, "vsel" , kVA , D_A_B_C , kVmx, "Vector Conditional Select" ), + INSTRUCTION(0x14000350, "vsel128" , kVX128 , D_A_B_D , kVmx, "Vector128 Conditional Select" ), + INSTRUCTION(0x100001c4, "vsl" , kVX , D_A_B , kVmx, "Vector Shift Left" ), + INSTRUCTION(0x10000104, "vslb" , kVX , D_A_B , kVmx, "Vector Shift Left Integer Byte" ), + INSTRUCTION(0x1000002c, "vsldoi" , kVA , D_A_B_C , kVmx, "Vector Shift Left Double by Octet Immediate" ), + INSTRUCTION(0x10000010, "vsldoi128" , kVX128_5, D_A_B_I , kVmx, "Vector128 Shift Left Double by Octet Immediate" ), + INSTRUCTION(0x10000144, "vslh" , kVX , D_A_B , kVmx, "Vector Shift Left Integer Half Word" ), + INSTRUCTION(0x1000040c, "vslo" , kVX , D_A_B , kVmx, "Vector Shift Left by Octet" ), + INSTRUCTION(0x14000390, "vslo128" , kVX128 , D_A_B , kVmx, "Vector128 Shift Left Octet" ), + INSTRUCTION(0x10000184, "vslw" , kVX , D_A_B , kVmx, "Vector Shift Left Integer Word" ), + INSTRUCTION(0x180000d0, "vslw128" , kVX128 , D_A_B , kVmx, "Vector128 Shift Left Integer Word" ), + INSTRUCTION(0x1000020c, "vspltb" , kVX , D_A_B , kVmx, "Vector Splat Byte" ), + INSTRUCTION(0x1000024c, "vsplth" , kVX , D_A_B , kVmx, "Vector Splat Half Word" ), + INSTRUCTION(0x1000030c, "vspltisb" , kVX , D_A_B , kVmx, "Vector Splat Immediate Signed Byte" ), + INSTRUCTION(0x1000034c, "vspltish" , kVX , D_A_B , kVmx, "Vector Splat Immediate Signed Half Word" ), + INSTRUCTION(0x1000038c, "vspltisw" , kVX , D_A_B , kVmx, "Vector Splat Immediate Signed Word" ), + INSTRUCTION(0x18000770, "vspltisw128" , kVX128_3, D_B_SIMM , kVmx, "Vector128 Splat Immediate Signed Word" ), + INSTRUCTION(0x1000028c, "vspltw" , kVX , D_A_B , kVmx, "Vector Splat Word" ), + INSTRUCTION(0x18000730, "vspltw128" , kVX128_3, D_B_SIMM , kVmx, "Vector128 Splat Word" ), + INSTRUCTION(0x100002c4, "vsr" , kVX , D_A_B , kVmx, "Vector Shift Right" ), + INSTRUCTION(0x10000304, "vsrab" , kVX , D_A_B , kVmx, "Vector Shift Right Algebraic Byte" ), + INSTRUCTION(0x10000344, "vsrah" , kVX , D_A_B , kVmx, "Vector Shift Right Algebraic Half Word" ), + INSTRUCTION(0x10000384, "vsraw" , kVX , D_A_B , kVmx, "Vector Shift Right Algebraic Word" ), + INSTRUCTION(0x18000150, "vsraw128" , kVX128 , D_A_B , kVmx, "Vector128 Shift Right Arithmetic Word" ), + INSTRUCTION(0x10000204, "vsrb" , kVX , D_A_B , kVmx, "Vector Shift Right Byte" ), + INSTRUCTION(0x10000244, "vsrh" , kVX , D_A_B , kVmx, "Vector Shift Right Half Word" ), + INSTRUCTION(0x1000044c, "vsro" , kVX , D_A_B , kVmx, "Vector Shift Right Octet" ), + INSTRUCTION(0x140003d0, "vsro128" , kVX128 , D_A_B , kVmx, "Vector128 Shift Right Octet" ), + INSTRUCTION(0x10000284, "vsrw" , kVX , D_A_B , kVmx, "Vector Shift Right Word" ), + INSTRUCTION(0x180001d0, "vsrw128" , kVX128 , D_A_B , kVmx, "Vector128 Shift Right Word" ), + INSTRUCTION(0x10000580, "vsubcuw" , kVX , D_A_B , kVmx, "Vector Subtract Carryout Unsigned Word" ), + INSTRUCTION(0x1000004a, "vsubfp" , kVX , D_A_B , kVmx, "Vector Subtract Floating Point" ), + INSTRUCTION(0x14000050, "vsubfp128" , kVX128 , D_A_B , kVmx, "Vector128 Subtract Floating Point" ), + INSTRUCTION(0x10000700, "vsubsbs" , kVX , D_A_B , kVmx, "Vector Subtract Signed Byte Saturate" ), + INSTRUCTION(0x10000740, "vsubshs" , kVX , D_A_B , kVmx, "Vector Subtract Signed Half Word Saturate" ), + INSTRUCTION(0x10000780, "vsubsws" , kVX , D_A_B , kVmx, "Vector Subtract Signed Word Saturate" ), + INSTRUCTION(0x10000400, "vsububm" , kVX , D_A_B , kVmx, "Vector Subtract Unsigned Byte Modulo" ), + INSTRUCTION(0x10000600, "vsububs" , kVX , D_A_B , kVmx, "Vector Subtract Unsigned Byte Saturate" ), + INSTRUCTION(0x10000440, "vsubuhm" , kVX , D_A_B , kVmx, "Vector Subtract Unsigned Half Word Modulo" ), + INSTRUCTION(0x10000640, "vsubuhs" , kVX , D_A_B , kVmx, "Vector Subtract Unsigned Half Word Saturate" ), + INSTRUCTION(0x10000480, "vsubuwm" , kVX , D_A_B , kVmx, "Vector Subtract Unsigned Word Modulo" ), + INSTRUCTION(0x10000680, "vsubuws" , kVX , D_A_B , kVmx, "Vector Subtract Unsigned Word Saturate" ), + INSTRUCTION(0x10000688, "vsum2sws" , kVX , D_A_B , kVmx, "Vector Sum Across Partial (1/2) Signed Word Saturate" ), + INSTRUCTION(0x10000708, "vsum4sbs" , kVX , D_A_B , kVmx, "Vector Sum Across Partial (1/4) Signed Byte Saturate" ), + INSTRUCTION(0x10000648, "vsum4shs" , kVX , D_A_B , kVmx, "Vector Sum Across Partial (1/4) Signed Half Word Saturate" ), + INSTRUCTION(0x10000608, "vsum4ubs" , kVX , D_A_B , kVmx, "Vector Sum Across Partial (1/4) Unsigned Byte Saturate" ), + INSTRUCTION(0x10000788, "vsumsws" , kVX , D_A_B , kVmx, "Vector Sum Across Signed Word Saturate" ), + INSTRUCTION(0x180007f0, "vupkd3d128" , kVX128_3, D_B_SIMM , kVmx, "Vector128 Unpack D3Dtype" ), + INSTRUCTION(0x1000034e, "vupkhpx" , kVX , D_A_B , kVmx, "Vector Unpack High Pixel" ), + INSTRUCTION(0x1000020e, "vupkhsb" , kVX , D_A_B , kVmx, "Vector Unpack High Signed Byte" ), + INSTRUCTION(0x18000380, "vupkhsb128" , kVX128 , D_B , kVmx, "Vector128 Unpack High Signed Byte" ), + INSTRUCTION(0x1000024e, "vupkhsh" , kVX , D_A_B , kVmx, "Vector Unpack High Signed Half Word" ), + INSTRUCTION(0x100003ce, "vupklpx" , kVX , D_A_B , kVmx, "Vector Unpack Low Pixel" ), + INSTRUCTION(0x1000028e, "vupklsb" , kVX , D_A_B , kVmx, "Vector Unpack Low Signed Byte" ), + INSTRUCTION(0x180003c0, "vupklsb128" , kVX128 , D_B , kVmx, "Vector128 Unpack Low Signed Byte" ), + INSTRUCTION(0x100002ce, "vupklsh" , kVX , D_A_B , kVmx, "Vector Unpack Low Signed Half Word" ), + INSTRUCTION(0x100004c4, "vxor" , kVX , D_A_B , kVmx, "Vector Logical XOR" ), + INSTRUCTION(0x14000310, "vxor128" , kVX128 , D_A_B , kVmx, "Vector128 Logical XOR" ), + INSTRUCTION(0x68000000, "xori" , kD , S_A_UIMM , kInt, "XOR Immediate" ), + INSTRUCTION(0x6c000000, "xoris" , kD , S_A_UIMM , kInt, "XOR Immediate Shifted" ), + INSTRUCTION(0x7c000278, "xorx" , kX , S_A_B_Rc , kInt, "XOR" ), +}; +static_assert(sizeof(ppc_opcode_table) / sizeof(PPCOpcodeInfo) == static_cast(PPCOpcode::kInvalid), "PPC table mismatch - rerun ppc-table-gen"); + +const PPCOpcodeInfo& GetOpcodeInfo(PPCOpcode opcode) { + return ppc_opcode_table[static_cast(opcode)]; +} + +} // namespace ppc +} // namespace cpu +} // namespace xe diff --git a/src/xenia/cpu/ppc/ppc_scanner.cc b/src/xenia/cpu/ppc/ppc_scanner.cc index 253376dee..2ec6f3052 100644 --- a/src/xenia/cpu/ppc/ppc_scanner.cc +++ b/src/xenia/cpu/ppc/ppc_scanner.cc @@ -17,6 +17,7 @@ #include "xenia/base/profiling.h" #include "xenia/cpu/ppc/ppc_frontend.h" #include "xenia/cpu/ppc/ppc_instr.h" +#include "xenia/cpu/ppc/ppc_opcode_info.h" #include "xenia/cpu/processor.h" #if 0 @@ -63,23 +64,24 @@ bool PPCScanner::Scan(GuestFunction* function, DebugInfo* debug_info) { size_t blocks_found = 0; bool in_block = false; bool starts_with_mfspr_lr = false; - InstrData i; while (true) { - i.address = address; - i.code = xe::load_and_swap(memory->TranslateVirtual(address)); + uint32_t code = + xe::load_and_swap(memory->TranslateVirtual(address)); // If we fetched 0 assume that we somehow hit one of the awesome // 'no really we meant to end after that bl' functions. - if (!i.code) { + if (!code) { LOGPPC("function end %.8X (0x00000000 read)", address); // Don't include the 0's. address -= 4; break; } - // TODO(benvanik): find a way to avoid using the opcode tables. - // This lookup is *expensive* and should be avoided when scanning. - i.type = GetInstrType(i.code); + auto opcode = LookupOpcode(code); + + InstrData i; + i.address = address; + i.code = code; // TODO(benvanik): switch on instruction metadata. ++address_reference_count; @@ -88,7 +90,7 @@ bool PPCScanner::Scan(GuestFunction* function, DebugInfo* debug_info) { // Check if the function starts with a mfspr lr, as that's a good indication // of whether or not this is a normal function with a prolog/epilog. // Some valid leaf functions won't have this, but most will. - if (address == start_address && i.type && i.type->opcode == 0x7C0002A6 && + if (address == start_address && opcode == PPCOpcode::mfspr && (((i.XFX.spr & 0x1F) << 5) | ((i.XFX.spr >> 5) & 0x1F)) == 8) { starts_with_mfspr_lr = true; } @@ -100,12 +102,12 @@ bool PPCScanner::Scan(GuestFunction* function, DebugInfo* debug_info) { bool ends_fn = false; bool ends_block = false; - if (!i.type) { + if (opcode == PPCOpcode::kInvalid) { // Invalid instruction. // We can just ignore it because there's (very little)/no chance it'll // affect flow control. - LOGPPC("Invalid instruction at %.8X: %.8X", address, i.code); - } else if (i.code == 0x4E800020) { + LOGPPC("Invalid instruction at %.8X: %.8X", address, code); + } else if (code == 0x4E800020) { // blr -- unconditional branch to LR. // This is generally a return. if (furthest_target > address) { @@ -117,7 +119,7 @@ bool PPCScanner::Scan(GuestFunction* function, DebugInfo* debug_info) { ends_fn = true; } ends_block = true; - } else if (i.code == 0x4E800420) { + } else if (code == 0x4E800420) { // bctr -- unconditional branch to CTR. // This is generally a jump to a function pointer (non-return). // This is almost always a jump table. @@ -131,7 +133,7 @@ bool PPCScanner::Scan(GuestFunction* function, DebugInfo* debug_info) { ends_fn = true; } ends_block = true; - } else if (i.type->opcode == 0x48000000) { + } else if (opcode == PPCOpcode::bx) { // b/ba/bl/bla uint32_t target = (uint32_t)XEEXTS26(i.I.LI << 2) + (i.I.AA ? 0 : (int32_t)address); @@ -209,7 +211,7 @@ bool PPCScanner::Scan(GuestFunction* function, DebugInfo* debug_info) { } } ends_block = true; - } else if (i.type->opcode == 0x40000000) { + } else if (opcode == PPCOpcode::bcx) { // bc/bca/bcl/bcla uint32_t target = (uint32_t)XEEXTS16(i.B.BD << 2) + (i.B.AA ? 0 : (int32_t)address); @@ -230,7 +232,7 @@ bool PPCScanner::Scan(GuestFunction* function, DebugInfo* debug_info) { } } ends_block = true; - } else if (i.type->opcode == 0x4C000020) { + } else if (opcode == PPCOpcode::bclrx) { // bclr/bclrl if (i.XL.LK) { LOGPPC("bclrl %.8X", address); @@ -238,7 +240,7 @@ bool PPCScanner::Scan(GuestFunction* function, DebugInfo* debug_info) { LOGPPC("bclr %.8X", address); } ends_block = true; - } else if (i.type->opcode == 0x4C000420) { + } else if (opcode == PPCOpcode::bcctrx) { // bcctr/bcctrl if (i.XL.LK) { LOGPPC("bcctrl %.8X", address); @@ -299,17 +301,13 @@ std::vector PPCScanner::FindBlocks(GuestFunction* function) { uint32_t end_address = function->end_address(); bool in_block = false; uint32_t block_start = 0; - InstrData i; for (uint32_t address = start_address; address <= end_address; address += 4) { - i.address = address; - i.code = xe::load_and_swap(memory->TranslateVirtual(address)); - if (!i.code) { + uint32_t code = + xe::load_and_swap(memory->TranslateVirtual(address)); + if (!code) { continue; } - - // TODO(benvanik): find a way to avoid using the opcode tables. - // This lookup is *expensive* and should be avoided when scanning. - i.type = GetInstrType(i.code); + auto opcode = xe::cpu::ppc::LookupOpcode(code); if (!in_block) { in_block = true; @@ -317,30 +315,28 @@ std::vector PPCScanner::FindBlocks(GuestFunction* function) { } bool ends_block = false; - if (!i.type) { - // Invalid instruction. - } else if (i.code == 0x4E800020) { + if (code == 0x4E800020) { // blr -- unconditional branch to LR. ends_block = true; - } else if (i.code == 0x4E800420) { + } else if (code == 0x4E800420) { // bctr -- unconditional branch to CTR. // This is almost always a jump table. // TODO(benvanik): decode jump tables. ends_block = true; - } else if (i.type->opcode == 0x48000000) { + } else if (opcode == PPCOpcode::bx) { // b/ba/bl/bla // uint32_t target = // (uint32_t)XEEXTS26(i.I.LI << 2) + (i.I.AA ? 0 : (int32_t)address); ends_block = true; - } else if (i.type->opcode == 0x40000000) { + } else if (opcode == PPCOpcode::bcx) { // bc/bca/bcl/bcla // uint32_t target = // (uint32_t)XEEXTS16(i.B.BD << 2) + (i.B.AA ? 0 : (int32_t)address); ends_block = true; - } else if (i.type->opcode == 0x4C000020) { + } else if (opcode == PPCOpcode::bclrx) { // bclr/bclrl ends_block = true; - } else if (i.type->opcode == 0x4C000420) { + } else if (opcode == PPCOpcode::bcctrx) { // bcctr/bcctrl ends_block = true; } diff --git a/src/xenia/cpu/ppc/ppc_translator.cc b/src/xenia/cpu/ppc/ppc_translator.cc index 08df5085a..b7bf72fd7 100644 --- a/src/xenia/cpu/ppc/ppc_translator.cc +++ b/src/xenia/cpu/ppc/ppc_translator.cc @@ -219,14 +219,11 @@ void PPCTranslator::DumpSource(GuestFunction* function, uint32_t start_address = function->address(); uint32_t end_address = function->end_address(); - InstrData i; auto block_it = blocks.begin(); for (uint32_t address = start_address, offset = 0; address <= end_address; address += 4, offset++) { - i.address = address; - i.code = xe::load_and_swap(memory->TranslateVirtual(address)); - // TODO(benvanik): find a way to avoid using the opcode tables. - i.type = GetInstrType(i.code); + uint32_t code = + xe::load_and_swap(memory->TranslateVirtual(address)); // Check labels. if (block_it != blocks.end() && block_it->start_address == address) { @@ -235,8 +232,8 @@ void PPCTranslator::DumpSource(GuestFunction* function, ++block_it; } - string_buffer->AppendFormat("%.8X %.8X ", address, i.code); - DisasmPPC(&i, string_buffer); + string_buffer->AppendFormat("%.8X %.8X ", address, code); + DisasmPPC(address, code, string_buffer); string_buffer->Append('\n'); } } diff --git a/src/xenia/cpu/ppc/testing/instr_vcmpxxfp128.s b/src/xenia/cpu/ppc/testing/instr_vcmpxxfp128.s index ea70e055d..ee02c0753 100644 --- a/src/xenia/cpu/ppc/testing/instr_vcmpxxfp128.s +++ b/src/xenia/cpu/ppc/testing/instr_vcmpxxfp128.s @@ -30,3 +30,14 @@ test_vcmpxxfp128_3: #_ REGISTER_OUT v4 [3f800000, 3f800000, 3f800000, 3f800000] #_ REGISTER_OUT v5 [3f800001, 3f800001, 3f800001, 3f800001] #_ REGISTER_OUT r3 0x00000020 + +test_vcmpxxfp128_4: + #_ REGISTER_IN v4 [3f800000, 3f800000, 3f800000, 3f800000] + #_ REGISTER_IN v5 [3f800001, 3f800001, 3f800001, 3f800001] + vcmpgefp128. v3, v4, v5 + mfocrf r3, 2 # cr6 + blr + #_ REGISTER_OUT v3 [00000000, 00000000, 00000000, 00000000] + #_ REGISTER_OUT v4 [3f800000, 3f800000, 3f800000, 3f800000] + #_ REGISTER_OUT v5 [3f800001, 3f800001, 3f800001, 3f800001] + #_ REGISTER_OUT r3 0x00000020 diff --git a/src/xenia/debug/debugger.cc b/src/xenia/debug/debugger.cc index 46523565a..2cfe0ddae 100644 --- a/src/xenia/debug/debugger.cc +++ b/src/xenia/debug/debugger.cc @@ -24,6 +24,7 @@ #include "xenia/cpu/backend/code_cache.h" #include "xenia/cpu/function.h" #include "xenia/cpu/ppc/ppc_instr.h" +#include "xenia/cpu/ppc/ppc_opcode_info.h" #include "xenia/cpu/processor.h" #include "xenia/cpu/stack_walker.h" #include "xenia/emulator.h" @@ -47,6 +48,7 @@ namespace xe { namespace debug { using xe::cpu::ThreadState; +using xe::cpu::ppc::PPCOpcode; using xe::kernel::XObject; using xe::kernel::XThread; @@ -723,10 +725,8 @@ uint32_t Debugger::CalculateNextGuestInstruction( i.address = current_pc; i.code = xe::load_and_swap( emulator_->memory()->TranslateVirtual(i.address)); - i.type = xe::cpu::ppc::GetInstrType(i.code); - if (!i.type) { - return current_pc + 4; - } else if (i.code == 0x4E800020) { + auto opcode = xe::cpu::ppc::LookupOpcode(i.code); + if (i.code == 0x4E800020) { // blr -- unconditional branch to LR. uint32_t target_pc = static_cast(thread_info->guest_context.lr); return target_pc; @@ -734,13 +734,13 @@ uint32_t Debugger::CalculateNextGuestInstruction( // bctr -- unconditional branch to CTR. uint32_t target_pc = static_cast(thread_info->guest_context.ctr); return target_pc; - } else if (i.type->opcode == 0x48000000) { + } else if (opcode == PPCOpcode::bx) { // b/ba/bl/bla uint32_t target_pc = static_cast(xe::cpu::ppc::XEEXTS26(i.I.LI << 2)) + (i.I.AA ? 0u : i.address); return target_pc; - } else if (i.type->opcode == 0x40000000) { + } else if (opcode == PPCOpcode::bcx) { // bc/bca/bcl/bcla uint32_t target_pc = static_cast(xe::cpu::ppc::XEEXTS16(i.B.BD << 2)) + @@ -748,13 +748,13 @@ uint32_t Debugger::CalculateNextGuestInstruction( bool test_passed = TestPpcCondition(&thread_info->guest_context, i.B.BO, i.B.BI, true, true); return test_passed ? target_pc : current_pc + 4; - } else if (i.type->opcode == 0x4C000020) { + } else if (opcode == PPCOpcode::bclrx) { // bclr/bclrl uint32_t target_pc = static_cast(thread_info->guest_context.lr); bool test_passed = TestPpcCondition(&thread_info->guest_context, i.XL.BO, i.XL.BI, true, true); return test_passed ? target_pc : current_pc + 4; - } else if (i.type->opcode == 0x4C000420) { + } else if (opcode == PPCOpcode::bcctrx) { // bcctr/bcctrl uint32_t target_pc = static_cast(thread_info->guest_context.ctr); bool test_passed = TestPpcCondition(&thread_info->guest_context, i.XL.BO, diff --git a/src/xenia/debug/ui/debug_window.cc b/src/xenia/debug/ui/debug_window.cc index 3b6ebaa62..eb7ebda88 100644 --- a/src/xenia/debug/ui/debug_window.cc +++ b/src/xenia/debug/ui/debug_window.cc @@ -502,12 +502,10 @@ void DebugWindow::DrawGuestFunctionSource() { ImGui::Text(" %c ", is_current_instr ? '>' : ' '); ImGui::SameLine(); - cpu::ppc::InstrData i; - i.address = address; - i.code = xe::load_and_swap(memory->TranslateVirtual(address)); - i.type = cpu::ppc::GetInstrType(i.code); - cpu::ppc::DisasmPPC(&i, &str); - ImGui::Text("%.8X %.8X %s", address, i.code, str.GetString()); + uint32_t code = + xe::load_and_swap(memory->TranslateVirtual(address)); + cpu::ppc::DisasmPPC(address, code, &str); + ImGui::Text("%.8X %.8X %s", address, code, str.GetString()); str.Reset(); if (is_current_instr) { diff --git a/src/xenia/kernel/xam/xam_ui.cc b/src/xenia/kernel/xam/xam_ui.cc index 9d7984e42..88be3e335 100644 --- a/src/xenia/kernel/xam/xam_ui.cc +++ b/src/xenia/kernel/xam/xam_ui.cc @@ -298,6 +298,10 @@ dword_result_t XamShowDeviceSelectorUI(dword_t user_index, dword_t content_type, case 3: // title/publisher update? *device_id_ptr = 0xF00D0000 | 0x0003; break; + default: + assert_unhandled_case(content_type); + *device_id_ptr = 0xF00D0000 | 0x0001; + break; } if (overlapped) { diff --git a/tools/ppc-instructions.xml b/tools/ppc-instructions.xml new file mode 100644 index 000000000..53a8f4da3 --- /dev/null +++ b/tools/ppc-instructions.xml @@ -0,0 +1,466 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/ppc-table-gen.py b/tools/ppc-table-gen.py new file mode 100644 index 000000000..796568239 --- /dev/null +++ b/tools/ppc-table-gen.py @@ -0,0 +1,345 @@ +#!/usr/bin/env python + +# Copyright 2015 Ben Vanik & shuffle2. All Rights Reserved. + +"""PPC instruction table generator. + +Generates various headers/sources for looking up and handling PPC instructions. + +This is based on shuffle2's PPC generator: +https://gist.github.com/shuffle2/10015968 +""" + +__author__ = 'ben.vanik@gmail.com (Ben Vanik)' + +import os +import sys +from xml.etree.ElementTree import ElementTree, Element, SubElement, tostring, dump + + +self_path = os.path.dirname(os.path.abspath(__file__)) + + +class Insn: + pass + + +def bit_extract(x, leftmost, rightmost): + return (x >> (32 - 1 - rightmost)) & ((1 << (rightmost - leftmost + 1)) - 1) + + +extended_opcode_bits = { + 'X': [(21, 30)], + 'XL': [(21, 30)], + 'XFX': [(21, 30)], + 'XFL': [(21, 30)], + 'VX': [(21, 31)], + 'VX128': [(22, 25), (27, 27)], + 'VX128_1': [(21, 27), (30, 31)], + 'VX128_2': [(22, 22), (27, 27)], + 'VX128_3': [(21, 27)], + 'VX128_4': [(21, 23), (26, 27)], + 'VX128_5': [(27, 27)], + 'VX128_R': [(22, 24), (27, 27)], + 'VX128_P': [(21, 22), (26, 27)], + 'VC': [(22, 31)], + 'VA': [(26, 31)], + 'XO': [(22, 30)], + 'XW': [(25, 30)], + 'A': [(26, 30)], + 'DS': [(30, 31)], + 'MD': [(27, 30)], + 'MDS': [(27, 30)], + 'MDSH': [(27, 29)], + 'XS': [(21, 29)], + 'DCBZ': [(6, 10), (21, 30)], # like X + } + + +def opcode_primary(insn): + return bit_extract(insn, 0, 5) + + +def opcode_extended(insn, form): + if form in extended_opcode_bits: + parts = extended_opcode_bits[form] + value = 0 + shift = 0 + for part in parts: + shift = max(shift, part[1]) + for part in parts: + part_value = bit_extract(insn, part[0], part[1]) + value = value | (part_value << (shift - part[1])) + return value + else: + return -1 + + +def parse_insns(filename): + root = ElementTree(file = filename) + insns = [] + # Convert to python types + for e in root.findall('.//insn'): + i = Insn() + i.desc = e.attrib['desc'] + i.form = e.attrib['form'] + i.group = e.attrib['group'] + i.mnem = e.attrib['mnem'] + i.opcode = int(e.attrib['opcode'], 16) + i.subform = e.attrib['sub-form'] + i.op_primary = opcode_primary(i.opcode) + i.op_extended = opcode_extended(i.opcode, i.form) + insns.append(i) + return insns + + +def c_mnem(x): + return x.replace('.', 'x') + + +def c_subform(x): + x = x.replace('-', '_') + if x[0] >= '0' and x[0] <= '9': + x = '_' + x + return x + + +def c_group(x): + return 'k' + x[0].upper() + x[1:] + + +def c_bool(x): + return 'true' if x else 'false' + + +def generate_opcodes(insns): + l = [] + TAB = ' ' * 2 + def w0(x): l.append(x) + def w1(x): w0(TAB * 1 + x) + def w2(x): w0(TAB * 2 + x) + def w3(x): w0(TAB * 3 + x) + + w0('// This code was autogenerated by %s. Do not modify!' % (sys.argv[0])) + w0('// clang-format off') + w0('#ifndef XENIA_CPU_PPC_PPC_OPCODE_H_') + w0('#define XENIA_CPU_PPC_PPC_OPCODE_H_') + w0('') + w0('#include ') + w0('') + w0('namespace xe {') + w0('namespace cpu {') + w0('namespace ppc {') + w0('') + + for i in insns: + i.mnem = c_mnem(i.mnem) + i.subform = c_subform(i.subform) + insns = sorted(insns, key = lambda i: i.mnem) + + w0('// All PPC opcodes in the same order they appear in ppc_instr_table.h:') + w0('enum class PPCOpcode : uint32_t {') + for i in insns: + w1('%s,' % (i.mnem)) + w1('kInvalid,') + w0('};') + + w0('') + w0('} // namespace ppc') + w0('} // namespace cpu') + w0('} // namespace xe') + w0('') + w0('#endif // XENIA_CPU_PPC_PPC_OPCODE_H_') + w0('') + + return '\n'.join(l) + + +def generate_table(insns): + l = [] + TAB = ' ' * 2 + def w0(x): l.append(x) + def w1(x): w0(TAB * 1 + x) + def w2(x): w0(TAB * 2 + x) + def w3(x): w0(TAB * 3 + x) + + w0('// This code was autogenerated by %s. Do not modify!' % (sys.argv[0])) + w0('// clang-format off') + w0('#include ') + w0('') + w0('#include "xenia/cpu/ppc/ppc_opcode.h"') + w0('#include "xenia/cpu/ppc/ppc_opcode_info.h"') + w0('') + w0('namespace xe {') + w0('namespace cpu {') + w0('namespace ppc {') + w0('') + + for i in insns: + i.mnem = '"' + c_mnem(i.mnem) + '"' + i.form = c_group(i.form) + i.subform = c_subform(i.subform) + i.desc = '"' + i.desc + '"' + i.group = c_group(i.group) + + mnem_len = len(max(insns, key = lambda i: len(i.mnem)).mnem) + form_len = len(max(insns, key = lambda i: len(i.form)).form) + subform_len = len(max(insns, key = lambda i: len(i.subform)).subform) + desc_len = len(max(insns, key = lambda i: len(i.desc)).desc) + group_len = len(max(insns, key = lambda i: len(i.group)).group) + + insns = sorted(insns, key = lambda i: i.mnem) + + w0('#define INSTRUCTION(opcode, mnem, form, subform, group, desc) \\') + w0(' {opcode, mnem, PPCOpcodeFormat::form, PPCOpcodeGroup::group, desc}') + w0('PPCOpcodeInfo ppc_opcode_table[] = {') + fmt = 'INSTRUCTION(' + ', '.join([ + '0x%08x', + '%-' + str(mnem_len) + 's', + '%-' + str(form_len) + 's', + '%-' + str(subform_len) + 's', + '%-' + str(group_len) + 's', + '%-' + str(desc_len) + 's', + ]) + '),' + for i in insns: + w1(fmt % (i.opcode, i.mnem, i.form, i.subform, i.group, i.desc)) + w0('};') + w0('static_assert(sizeof(ppc_opcode_table) / sizeof(PPCOpcodeInfo) == static_cast(PPCOpcode::kInvalid), "PPC table mismatch - rerun ppc-table-gen");') + w0('') + w0('const PPCOpcodeInfo& GetOpcodeInfo(PPCOpcode opcode) {') + w1('return ppc_opcode_table[static_cast(opcode)];') + w0('}') + + w0('') + w0('} // namespace ppc') + w0('} // namespace cpu') + w0('} // namespace xe') + w0('') + + return '\n'.join(l) + + +def generate_lookup(insns): + l = [] + TAB = ' ' * 2 + def w0(x): l.append(x) + def w1(x): w0(TAB * 1 + x) + def w2(x): w0(TAB * 2 + x) + def w3(x): w0(TAB * 3 + x) + + for i in insns: + i.mnem = c_mnem(i.mnem) + + w0('// This code was autogenerated by %s. Do not modify!' % (sys.argv[0])) + w0('// clang-format off') + w0('#include ') + w0('') + w0('#include "xenia/base/assert.h"') + w0('#include "xenia/cpu/ppc/ppc_opcode.h"') + w0('#include "xenia/cpu/ppc/ppc_opcode_info.h"') + w0('') + w0('namespace xe {') + w0('namespace cpu {') + w0('namespace ppc {') + w0('') + w0('constexpr uint32_t ExtractBits(uint32_t v, uint32_t a, uint32_t b) {') + w0(' return (v >> (32 - 1 - b)) & ((1 << (b - a + 1)) - 1);') + w0('}') + w0('') + w0('#define PPC_DECODER_MISS assert_always(); return PPCOpcode::kInvalid') + w0('#define PPC_DECODER_HIT(name) return PPCOpcode::name;') + w0('') + w0('PPCOpcode LookupOpcode(uint32_t code) {') + w1('switch (ExtractBits(code, 0, 5)) {') + + subtables = {} + for i in sorted(insns, key = lambda i: i.op_primary): + if i.op_primary not in subtables: subtables[i.op_primary] = [] + subtables[i.op_primary].append(i) + + for pri in sorted(subtables.iterkeys()): + # all the extended encodings (which we care about) end with bit 30. So we want to + # do the rest of the seach by bitscanning left from bit 30. This is simulated + # in the C switch-statement by creating leafs for each extended opcode, + # sorted by bitlength shortest to longest. + + if len(subtables[pri]) == 1: + for i in subtables[pri]: + # the primary opcode field fully identifies the opcode + w1('case %i: PPC_DECODER_HIT(%s);' % (i.op_primary, i.mnem)) + continue + + extract_groups = {} + for i in subtables[pri]: + form_parts = extended_opcode_bits[i.form] + shift = 0 + for form_part in form_parts: + shift = max(shift, form_part[1]) + extract_parts = [] + for form_part in form_parts: + extract_parts.append('(ExtractBits(code, %s, %s) << %s)' % (form_part[0], form_part[1], shift - form_part[1])) + extract_expression = '|'.join(extract_parts) + if extract_expression not in extract_groups: + extract_groups[extract_expression] = (i.form, extract_expression, []) + extract_groups[extract_expression][2].append(i) + + w1('case %i:' % (pri)) + for extract_expression in sorted(extract_groups.iterkeys()): + (form, extract_expression, group_insns) = extract_groups[extract_expression] + bit_span_low = 31 + bit_span_high = 0 + form_parts = extended_opcode_bits[form] + for form_part in form_parts: + bit_span_low = min(bit_span_low, form_part[0]) + bit_span_high = max(bit_span_high, form_part[1]) + bit_count = bit_span_high - bit_span_low + 1 + w2('switch (%s) {' % (extract_expression)) + for i in sorted(group_insns, key=lambda i: i.op_extended): + w3('case 0b%s: PPC_DECODER_HIT(%s);' % ( + ('{:0'+str(bit_count)+'b}').format(i.op_extended), + i.mnem)) + w2('}') + w2('PPC_DECODER_MISS;') + + w1('default: PPC_DECODER_MISS;') + + w1('}') + w0('}') + w0('') + w0('} // namespace ppc') + w0('} // namespace cpu') + w0('} // namespace xe') + w0('') + + # from this we can see some tables have bits which can be used to determine extended opcoded size: + # primary opcode 31: + # 01... = 9 bits (XO form), else 10 bits (X/XFX forms) + # primary opcode 63: + # 1.... = 7 bits (A form), else 10 bits (X/XFL forms) + # primary opcode 4: + # does not have small bit range to determine size, but you can just use the + # low 7 bits in order to "guess" the opcode. if you assume no invalid + # encodings are input, only the sequence ...0001000 actually *needs* the upper + # bits in order to differentiate the opcode (0100001000 = ps_abs, 0010001000 = ps_nabs) + # otherwise, the low 7bits can be used as the determinant, and a second comparison + # can be used against the real length of bits to fully match the extended opcode + # + # this approach can be generalized for all primary opcodes with extended opcodes of varying lengths: + # compare bits of smallest length, fall through to comparing larger sizes until found or failure + # with the optional optimization of discarding further compares for extended opcodes which + # share top bits with any other extended opcode (at the price of failing to detect invalid opcodes) + + return '\n'.join(l) + + +if __name__ == '__main__': + ppc_src_path = os.path.join(self_path, '..', 'src', 'xenia', 'cpu', 'ppc') + insns = parse_insns(os.path.join(self_path, 'ppc-instructions.xml')) + with open(os.path.join(ppc_src_path, 'ppc_opcode.h'), 'w') as f: + f.write(generate_opcodes(insns)) + insns = parse_insns(os.path.join(self_path, 'ppc-instructions.xml')) + with open(os.path.join(ppc_src_path, 'ppc_opcode_table.cc'), 'w') as f: + f.write(generate_table(insns)) + insns = parse_insns(os.path.join(self_path, 'ppc-instructions.xml')) + with open(os.path.join(ppc_src_path, 'ppc_opcode_lookup.cc'), 'w') as f: + f.write(generate_lookup(insns))