summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/cpu/powerpc/ppcfe.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/cpu/powerpc/ppcfe.c')
-rw-r--r--trunk/src/emu/cpu/powerpc/ppcfe.c1422
1 files changed, 1422 insertions, 0 deletions
diff --git a/trunk/src/emu/cpu/powerpc/ppcfe.c b/trunk/src/emu/cpu/powerpc/ppcfe.c
new file mode 100644
index 00000000000..d7c2a5e81b3
--- /dev/null
+++ b/trunk/src/emu/cpu/powerpc/ppcfe.c
@@ -0,0 +1,1422 @@
+/***************************************************************************
+
+ ppcfe.c
+
+ Front-end for PowerPC recompiler
+
+****************************************************************************
+
+ Copyright Aaron Giles
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name 'MAME' nor the names of its contributors may be
+ used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "ppcfe.h"
+#include "ppccom.h"
+
+
+//**************************************************************************
+// MACROS
+//**************************************************************************
+
+#define GPR_USED(desc, x) do { (desc).regin[0] |= REGFLAG_R(x); } while (0)
+#define GPR_USED_OR_ZERO(desc, x) do { (desc).regin[0] |= ((x) == 0 ? 0 : REGFLAG_R(x)); } while (0)
+#define GPR_MODIFIED(desc, x) do { (desc).regout[0] |= REGFLAG_R(x); } while (0)
+
+#define FPR_USED(desc, x) do { (desc).regin[1] |= REGFLAG_FR(x); } while (0)
+#define FPR_MODIFIED(desc, x) do { (desc).regout[1] |= REGFLAG_FR(x); } while (0)
+
+#define CR_USED(desc, x) do { (desc).regin[2] |= REGFLAG_CR(x); } while (0)
+#define CR_BIT_USED(desc, x) do { (desc).regin[2] |= REGFLAG_CR_BIT(x); } while (0)
+#define CR_MODIFIED(desc, x) do { (desc).regout[2] |= REGFLAG_CR(x); } while (0)
+#define CR_BIT_MODIFIED(desc, x) do { (desc).regout[2] |= REGFLAG_CR_BIT(x); } while (0)
+
+#define XER_CA_USED(desc) do { (desc).regin[3] |= REGFLAG_XER_CA; } while (0)
+#define XER_OV_USED(desc) do { (desc).regin[3] |= REGFLAG_XER_OV; } while (0)
+#define XER_SO_USED(desc) do { (desc).regin[3] |= REGFLAG_XER_SO; } while (0)
+#define XER_COUNT_USED(desc) do { (desc).regin[3] |= REGFLAG_XER_COUNT; } while (0)
+#define XER_CA_MODIFIED(desc) do { (desc).regout[3] |= REGFLAG_XER_CA; } while (0)
+#define XER_OV_MODIFIED(desc) do { (desc).regout[3] |= REGFLAG_XER_OV; } while (0)
+#define XER_SO_MODIFIED(desc) do { (desc).regout[3] |= REGFLAG_XER_SO; } while (0)
+#define XER_COUNT_MODIFIED(desc) do { (desc).regout[3] |= REGFLAG_XER_COUNT; } while (0)
+
+#define CTR_USED(desc) do { (desc).regin[3] |= REGFLAG_CTR; } while (0)
+#define CTR_MODIFIED(desc) do { (desc).regout[3] |= REGFLAG_CTR; } while (0)
+#define LR_USED(desc) do { (desc).regin[3] |= REGFLAG_LR; } while (0)
+#define LR_MODIFIED(desc) do { (desc).regout[3] |= REGFLAG_LR; } while (0)
+
+#define FPSCR_USED(desc, x) do { (desc).regin[3] |= REGFLAG_FPSCR(x); } while (0)
+#define FPSCR_MODIFIED(desc, x) do { (desc).regout[3] |= REGFLAG_FPSCR(x); } while (0)
+
+
+
+//**************************************************************************
+// PPC FRONTEND
+//**************************************************************************
+
+//-------------------------------------------------
+// ppc_frontend - constructor
+//-------------------------------------------------
+
+ppc_frontend::ppc_frontend(powerpc_state &state, UINT32 window_start, UINT32 window_end, UINT32 max_sequence)
+ : drc_frontend(*state.device, window_start, window_end, max_sequence),
+ m_context(state)
+{
+}
+
+
+//-------------------------------------------------
+// describe - build a description of a single
+// instruction
+//-------------------------------------------------
+
+bool ppc_frontend::describe(opcode_desc &desc, const opcode_desc *prev)
+{
+ UINT32 op, opswitch;
+ int regnum;
+
+ // compute the physical PC
+ if (!ppccom_translate_address(&m_context, AS_PROGRAM, TRANSLATE_FETCH, &desc.physpc))
+ {
+ // uh-oh: a page fault; leave the description empty and just if this is the first instruction, leave it empty and
+ // mark as needing to validate; otherwise, just end the sequence here
+ desc.flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION | OPFLAG_COMPILER_PAGE_FAULT | OPFLAG_VIRTUAL_NOOP | OPFLAG_END_SEQUENCE;
+ return true;
+ }
+
+ // fetch the opcode
+ op = desc.opptr.l[0] = m_context.direct->read_decrypted_dword(desc.physpc, m_context.codexor);
+
+ // all instructions are 4 bytes and default to a single cycle each
+ desc.length = 4;
+ desc.cycles = 1;
+
+ // parse the instruction
+ opswitch = op >> 26;
+ switch (opswitch)
+ {
+ case 0x02: // TDI - 64-bit only
+ case 0x1e: // 0x1e group - 64-bit only
+ case 0x3a: // 0x3a group - 64-bit only
+ case 0x3e: // 0x3e group - 64-bit only
+ return false;
+
+ case 0x03: // TWI
+ GPR_USED(desc, G_RA(op));
+ desc.flags |= OPFLAG_CAN_CAUSE_EXCEPTION;
+ if (is_603_class())
+ desc.cycles = 2; // 603
+ return true;
+
+ case 0x07: // MULLI
+ GPR_USED(desc, G_RA(op));
+ GPR_MODIFIED(desc, G_RD(op));
+ if (is_403_class())
+ desc.cycles = 4; // 4XX
+ else if (is_601_class())
+ desc.cycles = 5; // 601
+ else if (is_603_class())
+ desc.cycles = 2; // 603: 2-3
+ else
+ desc.cycles = 2; // ???
+ return true;
+
+ case 0x0e: // ADDI
+ case 0x0f: // ADDIS
+ GPR_USED_OR_ZERO(desc, G_RA(op));
+ GPR_MODIFIED(desc, G_RD(op));
+ return true;
+
+ case 0x0a: // CMPLI
+ case 0x0b: // CMPI
+ GPR_USED(desc, G_RA(op));
+ XER_SO_USED(desc);
+ CR_MODIFIED(desc, G_CRFD(op));
+ return true;
+
+ case 0x08: // SUBFIC
+ case 0x0c: // ADDIC
+ GPR_USED(desc, G_RA(op));
+ GPR_MODIFIED(desc, G_RD(op));
+ XER_CA_MODIFIED(desc);
+ return true;
+
+ case 0x0d: // ADDIC.
+ GPR_USED(desc, G_RA(op));
+ XER_SO_USED(desc);
+ GPR_MODIFIED(desc, G_RT(op));
+ XER_CA_MODIFIED(desc);
+ CR_MODIFIED(desc, 0);
+ return true;
+
+ case 0x10: // BCx
+ if (!(G_BO(op) & 0x10))
+ {
+ CR_BIT_USED(desc, G_BI(op));
+ // branch folding
+ if (prev == NULL || prev->regout[2] == 0)
+ desc.cycles = 0;
+ }
+ if (!(G_BO(op) & 0x04))
+ {
+ CTR_USED(desc);
+ CTR_MODIFIED(desc);
+ }
+ if (op & M_LK)
+ LR_MODIFIED(desc);
+ if ((G_BO(op) & 0x14) == 0x14)
+ desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
+ else
+ desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH;
+ desc.targetpc = (INT16)(G_BD(op) << 2) + ((op & M_AA) ? 0 : desc.pc);
+ if (desc.targetpc == desc.pc && desc.cycles == 0)
+ desc.cycles = 1;
+ return true;
+
+ case 0x11: // SC
+ if (!(m_context.cap & (PPCCAP_OEA | PPCCAP_4XX)))
+ return false;
+ desc.flags |= OPFLAG_WILL_CAUSE_EXCEPTION;
+ if (is_601_class())
+ desc.cycles = 16; // 601
+ else if (is_603_class())
+ desc.cycles = 3; // 603
+ else
+ desc.cycles = 3; // ???
+ return true;
+
+ case 0x12: // Bx
+ if (op & M_LK)
+ LR_MODIFIED(desc);
+ desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
+ desc.targetpc = ((INT32)(G_LI(op) << 8) >> 6) + ((op & M_AA) ? 0 : desc.pc);
+ // branch folding
+ if (desc.targetpc != desc.pc)
+ desc.cycles = 0;
+ return true;
+
+ case 0x13: // 0x13 group
+ return describe_13(op, desc, prev);
+
+ case 0x14: // RLWIMIx
+ GPR_USED(desc, G_RS(op));
+ GPR_USED(desc, G_RA(op));
+ GPR_MODIFIED(desc, G_RA(op));
+ if (op & M_RC)
+ {
+ XER_SO_USED(desc);
+ CR_MODIFIED(desc, 0);
+ }
+ return true;
+
+ case 0x15: // RLWINMx
+ GPR_USED(desc, G_RS(op));
+ GPR_MODIFIED(desc, G_RA(op));
+ if (op & M_RC)
+ {
+ XER_SO_USED(desc);
+ CR_MODIFIED(desc, 0);
+ }
+ return true;
+
+ case 0x17: // RLWNMx
+ GPR_USED(desc, G_RS(op));
+ GPR_USED(desc, G_RB(op));
+ GPR_MODIFIED(desc, G_RA(op));
+ if (op & M_RC)
+ {
+ XER_SO_USED(desc);
+ CR_MODIFIED(desc, 0);
+ }
+ return true;
+
+ case 0x18: // ORI
+ case 0x19: // ORIS
+ case 0x1a: // XORI
+ case 0x1b: // XORIS
+ GPR_USED(desc, G_RS(op));
+ GPR_MODIFIED(desc, G_RA(op));
+ return true;
+
+ case 0x1c: // ANDI.
+ case 0x1d: // ANDIS.
+ GPR_USED(desc, G_RS(op));
+ XER_SO_USED(desc);
+ GPR_MODIFIED(desc, G_RA(op));
+ CR_MODIFIED(desc, 0);
+ return true;
+
+ case 0x1f: // 0x1f group
+ return describe_1f(op, desc, prev);
+
+ case 0x20: // LWZ
+ case 0x22: // LBZ
+ case 0x28: // LHZ
+ case 0x2a: // LHA
+ GPR_USED_OR_ZERO(desc, G_RA(op));
+ GPR_MODIFIED(desc, G_RD(op));
+ desc.flags |= OPFLAG_READS_MEMORY;
+ return true;
+
+ case 0x21: // LWZU
+ case 0x23: // LBZU
+ case 0x29: // LHZU
+ case 0x2b: // LHAU
+ if (G_RA(op) == 0 || G_RA(op) == G_RD(op))
+ return false;
+ GPR_USED(desc, G_RA(op));
+ GPR_MODIFIED(desc, G_RD(op));
+ GPR_MODIFIED(desc, G_RA(op));
+ desc.flags |= OPFLAG_READS_MEMORY;
+ return true;
+
+ case 0x24: // STW
+ case 0x26: // STB
+ case 0x2c: // STH
+ GPR_USED_OR_ZERO(desc, G_RA(op));
+ GPR_USED(desc, G_RS(op));
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+ return true;
+
+ case 0x25: // STWU
+ case 0x27: // STBU
+ case 0x2d: // STHU
+ if (G_RA(op) == 0)
+ return false;
+ GPR_USED(desc, G_RA(op));
+ GPR_USED(desc, G_RS(op));
+ GPR_MODIFIED(desc, G_RA(op));
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+ return true;
+
+ case 0x2e: // LMW
+ GPR_USED_OR_ZERO(desc, G_RA(op));
+ for (regnum = G_RD(op); regnum < 32; regnum++)
+ GPR_MODIFIED(desc, regnum);
+ desc.flags |= OPFLAG_READS_MEMORY;
+ desc.cycles = 32 - G_RD(op);
+ return true;
+
+ case 0x2f: // STMW
+ GPR_USED_OR_ZERO(desc, G_RA(op));
+ for (regnum = G_RS(op); regnum < 32; regnum++)
+ GPR_USED(desc, regnum);
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+ desc.cycles = 32 - G_RS(op);
+ return true;
+
+ case 0x30: // LFS
+ case 0x32: // LFD
+ if (!(m_context.cap & PPCCAP_FPU))
+ return false;
+ GPR_USED_OR_ZERO(desc, G_RA(op));
+ FPR_MODIFIED(desc, G_RD(op));
+ desc.flags |= OPFLAG_READS_MEMORY;
+ return true;
+
+ case 0x31: // LFSU
+ case 0x33: // LFDU
+ if (!(m_context.cap & PPCCAP_FPU))
+ return false;
+ if (G_RA(op) == 0)
+ return false;
+ GPR_USED(desc, G_RA(op));
+ GPR_MODIFIED(desc, G_RA(op));
+ FPR_MODIFIED(desc, G_RD(op));
+ desc.flags |= OPFLAG_READS_MEMORY;
+ return true;
+
+ case 0x34: // STFS
+ case 0x36: // STFD
+ if (!(m_context.cap & PPCCAP_FPU))
+ return false;
+ GPR_USED_OR_ZERO(desc, G_RA(op));
+ FPR_USED(desc, G_RS(op));
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+ return true;
+
+ case 0x35: // STFSU
+ case 0x37: // STFDU
+ if (!(m_context.cap & PPCCAP_FPU))
+ return false;
+ if (G_RA(op) == 0)
+ return false;
+ GPR_USED(desc, G_RA(op));
+ GPR_MODIFIED(desc, G_RA(op));
+ FPR_USED(desc, G_RS(op));
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+ return true;
+
+ case 0x3b: // 0x3b group
+ return describe_3b(op, desc, prev);
+
+ case 0x3f: // 0x3f group
+ return describe_3f(op, desc, prev);
+ }
+
+ return false;
+}
+
+
+/*-------------------------------------------------
+ describe_instruction_13 - build a
+ description of a single instruction in the
+ 0x13 group
+-------------------------------------------------*/
+
+bool ppc_frontend::describe_13(UINT32 op, opcode_desc &desc, const opcode_desc *prev)
+{
+ UINT32 opswitch = (op >> 1) & 0x3ff;
+
+ switch (opswitch)
+ {
+ case 0x000: // MTCRF
+ CR_USED(desc, G_CRFS(op));
+ CR_MODIFIED(desc, G_CRFD(op));
+ // CR logical folding
+ if (prev == NULL || prev->regout[2] == 0)
+ desc.cycles = 0;
+ return true;
+
+ case 0x010: // BCLRx
+ LR_USED(desc);
+ if (!(G_BO(op) & 0x10))
+ CR_BIT_USED(desc, G_BI(op));
+ if (!(G_BO(op) & 0x04))
+ {
+ CTR_USED(desc);
+ CTR_MODIFIED(desc);
+ }
+ if (op & M_LK)
+ LR_MODIFIED(desc);
+ if ((G_BO(op) & 0x14) == 0x14)
+ desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
+ else
+ desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH;
+ desc.targetpc = BRANCH_TARGET_DYNAMIC;
+ return true;
+
+ case 0x021: // CRNOR
+ case 0x081: // CRANDC
+ case 0x0c1: // CRXOR
+ case 0x0e1: // CRNAND
+ case 0x101: // CRAND
+ case 0x121: // CREQV
+ case 0x1a1: // CRORC
+ case 0x1c1: // CROR
+ CR_BIT_USED(desc, G_CRBA(op));
+ CR_BIT_USED(desc, G_CRBB(op));
+ CR_BIT_MODIFIED(desc, G_CRBD(op));
+ // CR logical folding
+ if (prev == NULL || prev->regout[2] == 0)
+ desc.cycles = 0;
+ return true;
+
+ case 0x032: // RFI
+ if (!(m_context.cap & (PPCCAP_OEA | PPCCAP_4XX)))
+ return false;
+ desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CHANGE_MODES | OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE | OPFLAG_CAN_CAUSE_EXCEPTION;
+ desc.targetpc = BRANCH_TARGET_DYNAMIC;
+ if (is_601_class())
+ desc.cycles = 13; // 601
+ else if (is_603_class())
+ desc.cycles = 3; // 603
+ else
+ desc.cycles = 3; // ???
+ return true;
+
+ case 0x033: // RFCI
+ if (!(m_context.cap & PPCCAP_4XX))
+ return false;
+ desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CHANGE_MODES | OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE | OPFLAG_CAN_CAUSE_EXCEPTION;
+ desc.targetpc = BRANCH_TARGET_DYNAMIC;
+ return true;
+
+ case 0x096: // ISYNC
+ if (!(m_context.cap & (PPCCAP_VEA | PPCCAP_4XX)))
+ return false;
+ if (is_601_class())
+ desc.cycles = 6; // 601
+ return true;
+
+ case 0x210: // BCCTRx
+ CTR_USED(desc);
+ if (!(G_BO(op) & 0x10))
+ CR_BIT_USED(desc, G_BI(op));
+ if (!(G_BO(op) & 0x04))
+ return false;
+ if (op & M_LK)
+ LR_MODIFIED(desc);
+ if ((G_BO(op) & 0x14) == 0x14)
+ desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
+ else
+ desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH;
+ desc.targetpc = BRANCH_TARGET_DYNAMIC;
+ return true;
+ }
+
+ return false;
+}
+
+
+/*-------------------------------------------------
+ describe_instruction_1f - build a
+ description of a single instruction in the
+ 0x1f group
+-------------------------------------------------*/
+
+bool ppc_frontend::describe_1f(UINT32 op, opcode_desc &desc, const opcode_desc *prev)
+{
+ UINT32 opswitch = (op >> 1) & 0x3ff;
+ int spr, regnum;
+
+ switch (opswitch)
+ {
+ case 0x009: // MULHDUx - 64-bit only
+ case 0x015: // LDX - 64-bit only
+ case 0x01b: // SLDx - 64-bit only
+ case 0x035: // LDUX - 64-bit only
+ case 0x03a: // CNTLZDx - 64-bit only
+ case 0x044: // TD - 64-bit only
+ case 0x049: // MULHDx - 64-bit only
+ case 0x054: // LDARX - 64-bit only
+ case 0x095: // STDX - 64-bit only
+ case 0x0b5: // STDUX - 64-bit only
+ case 0x0d6: // STDCX. - 64-bit only
+ case 0x0e9: // MULLD - 64-bit only
+ case 0x2e9: // MULLDO - 64-bit only
+ case 0x155: // LWAX - 64-bit only
+ case 0x175: // LWAUX - 64-bit only
+ case 0x33a: // SRADIx - 64-bit only
+ case 0x33b: // SRADIx - 64-bit only
+ case 0x1b2: // SLBIE - 64-bit only
+ case 0x1c9: // DIVDUx - 64-bit only
+ case 0x3c9: // DIVDUOx - 64-bit only
+ case 0x1e9: // DIVDx - 64-bit only
+ case 0x3e9: // DIVDOx - 64-bit only
+ case 0x1f2: // SLBIA - 64-bit only
+ case 0x21b: // SRDx - 64-bit only
+ case 0x31a: // SRADx - 64-bit only
+ case 0x3da: // EXTSW - 64-bit only
+ return false;
+
+ case 0x000: // CMP
+ case 0x020: // CMPL
+ GPR_USED(desc, G_RA(op));
+ GPR_USED(desc, G_RB(op));
+ XER_SO_USED(desc);
+ CR_MODIFIED(desc, G_CRFD(op));
+ return true;
+
+ case 0x004: // TW
+ GPR_USED(desc, G_RA(op));
+ GPR_USED(desc, G_RB(op));
+ desc.flags |= OPFLAG_CAN_CAUSE_EXCEPTION;
+ if (is_603_class())
+ desc.cycles = 2; // 603
+ return true;
+
+ case 0x008: // SUBFCx
+ case 0x00a: // ADDCx
+ GPR_USED(desc, G_RA(op));
+ GPR_USED(desc, G_RB(op));
+ GPR_MODIFIED(desc, G_RD(op));
+ XER_CA_MODIFIED(desc);
+ if (op & M_RC)
+ {
+ XER_SO_USED(desc);
+ CR_MODIFIED(desc, 0);
+ }
+ return true;
+
+ case 0x088: // SUBFEx
+ case 0x08a: // ADDEx
+ GPR_USED(desc, G_RA(op));
+ GPR_USED(desc, G_RB(op));
+ XER_CA_USED(desc);
+ GPR_MODIFIED(desc, G_RD(op));
+ XER_CA_MODIFIED(desc);
+ if (op & M_RC)
+ {
+ XER_SO_USED(desc);
+ CR_MODIFIED(desc, 0);
+ }
+ return true;
+
+ case 0x0c8: // SUBFZEx
+ case 0x0ca: // ADDZEx
+ case 0x0e8: // SUBFMEx
+ case 0x0ea: // ADDMEx
+ GPR_USED(desc, G_RA(op));
+ XER_CA_USED(desc);
+ GPR_MODIFIED(desc, G_RD(op));
+ XER_CA_MODIFIED(desc);
+ if (op & M_RC)
+ {
+ XER_SO_USED(desc);
+ CR_MODIFIED(desc, 0);
+ }
+ return true;
+
+ case 0x00b: // MULHWUx
+ case 0x04b: // MULHWx
+ case 0x0eb: // MULLWx
+ GPR_USED(desc, G_RA(op));
+ GPR_USED(desc, G_RB(op));
+ GPR_MODIFIED(desc, G_RD(op));
+ if (op & M_RC)
+ {
+ XER_SO_USED(desc);
+ CR_MODIFIED(desc, 0);
+ }
+ if (is_403_class())
+ desc.cycles = 4; // 4XX
+ else if (is_601_class())
+ desc.cycles = 5; // 601: 5/9/10
+ else if (is_603_class())
+ desc.cycles = 2; // 603: 2,3,4,5,6
+ else
+ desc.cycles = 2; // ???
+ return true;
+
+ case 0x1cb: // DIVWUx
+ case 0x1eb: // DIVWx
+ GPR_USED(desc, G_RA(op));
+ GPR_USED(desc, G_RB(op));
+ GPR_MODIFIED(desc, G_RD(op));
+ if (op & M_RC)
+ {
+ XER_SO_USED(desc);
+ CR_MODIFIED(desc, 0);
+ }
+ if (is_403_class())
+ desc.cycles = 33; // 4XX
+ else if (is_601_class())
+ desc.cycles = 36; // 601
+ else if (is_603_class())
+ desc.cycles = 37; // 603
+ else
+ desc.cycles = 33; // ???
+ return true;
+
+ case 0x028: // SUBFx
+ case 0x10a: // ADDx
+ GPR_USED(desc, G_RA(op));
+ GPR_USED(desc, G_RB(op));
+ GPR_MODIFIED(desc, G_RD(op));
+ if (op & M_RC)
+ {
+ XER_SO_USED(desc);
+ CR_MODIFIED(desc, 0);
+ }
+ return true;
+
+ case 0x208: // SUBFCOx
+ case 0x20a: // ADDCOx
+ GPR_USED(desc, G_RA(op));
+ GPR_USED(desc, G_RB(op));
+ GPR_MODIFIED(desc, G_RD(op));
+ XER_OV_MODIFIED(desc);
+ XER_SO_MODIFIED(desc);
+ XER_CA_MODIFIED(desc);
+ if (op & M_RC)
+ CR_MODIFIED(desc, 0);
+ return true;
+
+ case 0x288: // SUBFEOx
+ case 0x28a: // ADDEOx
+ GPR_USED(desc, G_RA(op));
+ GPR_USED(desc, G_RB(op));
+ XER_CA_USED(desc);
+ GPR_MODIFIED(desc, G_RD(op));
+ XER_OV_MODIFIED(desc);
+ XER_SO_MODIFIED(desc);
+ XER_CA_MODIFIED(desc);
+ if (op & M_RC)
+ CR_MODIFIED(desc, 0);
+ return true;
+
+ case 0x2c8: // SUBFZEOx
+ case 0x2ca: // ADDZEOx
+ case 0x2e8: // SUBFMEOx
+ case 0x2ea: // ADDMEOx
+ GPR_USED(desc, G_RA(op));
+ XER_CA_USED(desc);
+ GPR_MODIFIED(desc, G_RD(op));
+ XER_OV_MODIFIED(desc);
+ XER_SO_MODIFIED(desc);
+ XER_CA_MODIFIED(desc);
+ if (op & M_RC)
+ CR_MODIFIED(desc, 0);
+ return true;
+
+ case 0x2eb: // MULLWOx
+ GPR_USED(desc, G_RA(op));
+ GPR_USED(desc, G_RB(op));
+ GPR_MODIFIED(desc, G_RD(op));
+ XER_OV_MODIFIED(desc);
+ XER_SO_MODIFIED(desc);
+ if (op & M_RC)
+ CR_MODIFIED(desc, 0);
+ if (is_403_class())
+ desc.cycles = 4; // 4XX
+ else if (is_601_class())
+ desc.cycles = 5; // 601: 5/9/10
+ else if (is_603_class())
+ desc.cycles = 2; // 603: 2,3,4,5,6
+ else
+ desc.cycles = 2; // ???
+ return true;
+
+ case 0x3cb: // DIVWUOx
+ case 0x3eb: // DIVWOx
+ GPR_USED(desc, G_RA(op));
+ GPR_USED(desc, G_RB(op));
+ GPR_MODIFIED(desc, G_RD(op));
+ XER_OV_MODIFIED(desc);
+ XER_SO_MODIFIED(desc);
+ if (op & M_RC)
+ CR_MODIFIED(desc, 0);
+ if (is_403_class())
+ desc.cycles = 33; // 4XX
+ else if (is_601_class())
+ desc.cycles = 36; // 601
+ else if (is_603_class())
+ desc.cycles = 37; // 603
+ else
+ desc.cycles = 33; // ???
+ return true;
+
+ case 0x228: // SUBFOx
+ case 0x30a: // ADDOx
+ GPR_USED(desc, G_RA(op));
+ GPR_USED(desc, G_RB(op));
+ GPR_MODIFIED(desc, G_RD(op));
+ XER_OV_MODIFIED(desc);
+ XER_SO_MODIFIED(desc);
+ if (op & M_RC)
+ CR_MODIFIED(desc, 0);
+ return true;
+
+ case 0x013: // MFCR
+ CR_USED(desc, 0);
+ CR_USED(desc, 1);
+ CR_USED(desc, 2);
+ CR_USED(desc, 3);
+ CR_USED(desc, 4);
+ CR_USED(desc, 5);
+ CR_USED(desc, 6);
+ CR_USED(desc, 7);
+ GPR_MODIFIED(desc, G_RD(op));
+ return true;
+
+ case 0x136: // ECIWX
+ if (!(m_context.cap & PPCCAP_VEA))
+ return false;
+ case 0x014: // LWARX
+ case 0x017: // LWZX
+ case 0x057: // LBZX
+ case 0x117: // LHZX
+ case 0x157: // LHAX
+ case 0x216: // LWBRX
+ case 0x316: // LHBRX
+ GPR_USED_OR_ZERO(desc, G_RA(op));
+ GPR_USED(desc, G_RB(op));
+ GPR_MODIFIED(desc, G_RD(op));
+ desc.flags |= OPFLAG_READS_MEMORY;
+ return true;
+
+ case 0x018: // SLWx
+ case 0x01c: // ANDx
+ case 0x03c: // ANDCx
+ case 0x07c: // NORx
+ case 0x11c: // EQVx
+ case 0x13c: // XORx
+ case 0x19c: // ORCx
+ case 0x1bc: // ORx
+ case 0x1dc: // NANDx
+ GPR_USED(desc, G_RS(op));
+ GPR_USED(desc, G_RB(op));
+ GPR_MODIFIED(desc, G_RA(op));
+ if (op & M_RC)
+ {
+ XER_SO_USED(desc);
+ CR_MODIFIED(desc, 0);
+ }
+ return true;
+
+ case 0x218: // SRWx
+ case 0x318: // SRAWx
+ GPR_USED(desc, G_RS(op));
+ GPR_USED(desc, G_RB(op));
+ GPR_MODIFIED(desc, G_RA(op));
+ XER_CA_MODIFIED(desc);
+ if (op & M_RC)
+ {
+ XER_SO_USED(desc);
+ CR_MODIFIED(desc, 0);
+ }
+ return true;
+
+ case 0x01a: // CNTLZWx
+ case 0x39a: // EXTSHx
+ case 0x3ba: // EXTSBx
+ GPR_USED(desc, G_RS(op));
+ GPR_MODIFIED(desc, G_RA(op));
+ if (op & M_RC)
+ {
+ XER_SO_USED(desc);
+ CR_MODIFIED(desc, 0);
+ }
+ return true;
+
+ case 0x036: // DCBST
+ case 0x056: // DCBF
+ case 0x0f6: // DCBTST
+ case 0x116: // DCBT
+ case 0x2f6: // DCBA
+ case 0x3d6: // ICBI
+ if (!(m_context.cap & (PPCCAP_VEA | PPCCAP_4XX)))
+ return false;
+ GPR_USED_OR_ZERO(desc, G_RA(op));
+ GPR_USED(desc, G_RB(op));
+ return true;
+
+ case 0x1d6: // DCBI
+ if (!(m_context.cap & (PPCCAP_OEA | PPCCAP_4XX)))
+ return false;
+ GPR_USED_OR_ZERO(desc, G_RA(op));
+ GPR_USED(desc, G_RB(op));
+ desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION;
+ return true;
+
+ case 0x037: // LWZUX
+ case 0x077: // LBZUX
+ case 0x137: // LHZUX
+ case 0x177: // LHAUX
+ if (G_RA(op) == 0 || G_RA(op) == G_RD(op))
+ return false;
+ GPR_USED(desc, G_RA(op));
+ GPR_USED(desc, G_RB(op));
+ GPR_MODIFIED(desc, G_RD(op));
+ GPR_MODIFIED(desc, G_RA(op));
+ desc.flags |= OPFLAG_READS_MEMORY;
+ return true;
+
+ case 0x153: // MFSPR
+ GPR_MODIFIED(desc, G_RD(op));
+ spr = compute_spr(G_SPR(op));
+ if (spr == SPR_LR)
+ LR_USED(desc);
+ if (spr == SPR_CTR)
+ CTR_USED(desc);
+ if (spr == SPR_XER)
+ {
+ XER_COUNT_USED(desc);
+ XER_CA_USED(desc);
+ XER_OV_USED(desc);
+ XER_SO_USED(desc);
+ }
+ if (spr & 0x010)
+ desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION;
+ if ((m_context.cap & PPCCAP_4XX) && spr == SPR4XX_TBLU)
+ desc.cycles = POWERPC_COUNT_READ_TBL;
+ else if ((m_context.cap & PPCCAP_VEA) && spr == SPRVEA_TBL_R)
+ desc.cycles = POWERPC_COUNT_READ_TBL;
+ else if ((m_context.cap & PPCCAP_OEA) && spr == SPROEA_DEC)
+ desc.cycles = POWERPC_COUNT_READ_DEC;
+ return true;
+
+ case 0x053: // MFMSR
+ GPR_MODIFIED(desc, G_RD(op));
+ desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION | OPFLAG_CAN_EXPOSE_EXTERNAL_INT;
+ if (is_601_class())
+ desc.cycles = 2; // 601
+ return true;
+
+ case 0x253: // MFSR
+ GPR_MODIFIED(desc, G_RD(op));
+ desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION;
+ return true;
+
+ case 0x293: // MFSRIN
+ GPR_USED(desc, G_RB(op));
+ GPR_MODIFIED(desc, G_RD(op));
+ desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION;
+ return true;
+
+ case 0x173: // MFTB
+ if (!(m_context.cap & PPCCAP_VEA))
+ return false;
+ GPR_MODIFIED(desc, G_RD(op));
+ spr = compute_spr(G_SPR(op));
+ if (spr == SPRVEA_TBL_R)
+ desc.cycles = POWERPC_COUNT_READ_TBL;
+ return true;
+
+ case 0x068: // NEGx
+ GPR_USED(desc, G_RA(op));
+ GPR_MODIFIED(desc, G_RD(op));
+ if (op & M_RC)
+ {
+ XER_SO_USED(desc);
+ CR_MODIFIED(desc, 0);
+ }
+ return true;
+
+ case 0x268: // NEGOx
+ GPR_USED(desc, G_RA(op));
+ GPR_MODIFIED(desc, G_RD(op));
+ XER_OV_MODIFIED(desc);
+ XER_SO_MODIFIED(desc);
+ if (op & M_RC)
+ CR_MODIFIED(desc, 0);
+ return true;
+
+ case 0x090: // MTCRF
+ GPR_USED(desc, G_RS(op));
+ if (G_CRM(op) & 0x80) CR_MODIFIED(desc, 0);
+ if (G_CRM(op) & 0x40) CR_MODIFIED(desc, 1);
+ if (G_CRM(op) & 0x20) CR_MODIFIED(desc, 2);
+ if (G_CRM(op) & 0x10) CR_MODIFIED(desc, 3);
+ if (G_CRM(op) & 0x08) CR_MODIFIED(desc, 4);
+ if (G_CRM(op) & 0x04) CR_MODIFIED(desc, 5);
+ if (G_CRM(op) & 0x02) CR_MODIFIED(desc, 6);
+ if (G_CRM(op) & 0x01) CR_MODIFIED(desc, 7);
+ return true;
+
+ case 0x092: // MTMSR
+ GPR_USED(desc, G_RS(op));
+ desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION | OPFLAG_CAN_CHANGE_MODES | OPFLAG_END_SEQUENCE;
+ if (is_601_class())
+ desc.cycles = 17; // 601
+ else if (is_603_class())
+ desc.cycles = 2; // 603
+ return true;
+
+ case 0x0d2: // MTSR
+ if (!(m_context.cap & PPCCAP_OEA))
+ return false;
+ GPR_USED(desc, G_RS(op));
+ desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION;
+ return true;
+
+ case 0x1d3: // MTSPR
+ GPR_USED(desc, G_RS(op));
+ spr = compute_spr(G_SPR(op));
+ if (spr == SPR_LR)
+ LR_MODIFIED(desc);
+ if (spr == SPR_CTR)
+ CTR_MODIFIED(desc);
+ if (spr == SPR_XER)
+ {
+ XER_COUNT_MODIFIED(desc);
+ XER_CA_MODIFIED(desc);
+ XER_OV_MODIFIED(desc);
+ XER_SO_MODIFIED(desc);
+ }
+ if (spr & 0x010)
+ desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION;
+ return true;
+
+ case 0x1b6: // ECOWX
+ if (!(m_context.cap & PPCCAP_VEA))
+ return false;
+ case 0x096: // STWCX.
+ case 0x097: // STWX
+ case 0x0d7: // STBX
+ case 0x197: // STHX
+ case 0x296: // STWBRX
+ case 0x396: // STHBRX
+ GPR_USED_OR_ZERO(desc, G_RA(op));
+ GPR_USED(desc, G_RB(op));
+ GPR_USED(desc, G_RS(op));
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+ return true;
+
+ case 0x0b7: // STWUX
+ case 0x0f7: // STBUX
+ case 0x1b7: // STHUX
+ if (G_RA(op) == 0)
+ return false;
+ GPR_USED(desc, G_RA(op));
+ GPR_USED(desc, G_RB(op));
+ GPR_USED(desc, G_RS(op));
+ GPR_MODIFIED(desc, G_RA(op));
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+ return true;
+
+ case 0x0f2: // MTSRIN
+ if (!(m_context.cap & PPCCAP_OEA))
+ return false;
+ GPR_USED(desc, G_RS(op));
+ GPR_USED(desc, G_RB(op));
+ desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION;
+ return true;
+
+ case 0x132: // TLBIE
+ if (!(m_context.cap & PPCCAP_OEA))
+ return false;
+ GPR_USED(desc, G_RB(op));
+ desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION;
+ return true;
+
+ case 0x172: // TLBIA
+ if (!(m_context.cap & PPCCAP_OEA) || (m_context.cap & PPCCAP_603_MMU))
+ return false;
+ desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION;
+ return true;
+
+ case 0x3d2: // TLBLD
+ case 0x3f2: // TLBLI
+ if (!(m_context.cap & PPCCAP_603_MMU) && !is_602_class())
+ return false;
+ desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION;
+ return true;
+
+ case 0x200: // MCRXR
+ XER_CA_USED(desc);
+ XER_OV_USED(desc);
+ XER_SO_USED(desc);
+ CR_MODIFIED(desc, G_CRFD(op));
+ XER_CA_MODIFIED(desc);
+ XER_OV_MODIFIED(desc);
+ XER_SO_MODIFIED(desc);
+ return true;
+
+ case 0x215: // LSWX
+ GPR_USED_OR_ZERO(desc, G_RA(op));
+ GPR_USED(desc, G_RB(op));
+ XER_COUNT_USED(desc);
+ for (regnum = 0; regnum < 32; regnum++)
+ GPR_MODIFIED(desc, regnum);
+ desc.flags |= OPFLAG_READS_MEMORY;
+ return true;
+
+ case 0x217: // LFSX
+ case 0x257: // LFDX
+ if (!(m_context.cap & PPCCAP_FPU))
+ return false;
+ GPR_USED_OR_ZERO(desc, G_RA(op));
+ GPR_USED(desc, G_RB(op));
+ FPR_MODIFIED(desc, G_RD(op));
+ desc.flags |= OPFLAG_READS_MEMORY;
+ return true;
+
+ case 0x236: // TLBSYNC
+ if (!(m_context.cap & PPCCAP_OEA))
+ return false;
+ desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION;
+ return true;
+
+ case 0x256: // SYNC
+ return true;
+
+ case 0x356: // EIEIO
+ if (!(m_context.cap & PPCCAP_VEA))
+ return false;
+ return true;
+
+ case 0x237: // LFSUX
+ case 0x277: // LFDUX
+ if (!(m_context.cap & PPCCAP_FPU))
+ return false;
+ if (G_RA(op) == 0)
+ return false;
+ GPR_USED(desc, G_RA(op));
+ GPR_USED(desc, G_RB(op));
+ GPR_MODIFIED(desc, G_RA(op));
+ FPR_MODIFIED(desc, G_RD(op));
+ desc.flags |= OPFLAG_READS_MEMORY;
+ return true;
+
+ case 0x255: // LSWI
+ GPR_USED_OR_ZERO(desc, G_RA(op));
+ for (regnum = 0; regnum < ((G_NB(op) - 1) & 0x1f) + 1; regnum += 4)
+ GPR_MODIFIED(desc, (G_RD(op) + regnum / 4) % 32);
+ desc.flags |= OPFLAG_READS_MEMORY;
+ desc.cycles = (((G_NB(op) - 1) & 0x1f) + 1 + 3) / 4;
+ return true;
+
+ case 0x295: // STSWX
+ GPR_USED_OR_ZERO(desc, G_RA(op));
+ GPR_USED(desc, G_RB(op));
+ XER_COUNT_USED(desc);
+ for (regnum = 0; regnum < 32; regnum++)
+ GPR_USED(desc, regnum);
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+ return true;
+
+ case 0x2d5: // STSWI
+ GPR_USED_OR_ZERO(desc, G_RA(op));
+ for (regnum = 0; regnum < ((G_NB(op) - 1) & 0x1f) + 1; regnum += 4)
+ GPR_USED(desc, (G_RD(op) + regnum / 4) % 32);
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+ desc.cycles = (((G_NB(op) - 1) & 0x1f) + 1 + 3) / 4;
+ return true;
+
+ case 0x297: // STFSX
+ case 0x2d7: // STFDX
+ case 0x3d7: // STFIWX
+ if (!(m_context.cap & PPCCAP_FPU))
+ return false;
+ GPR_USED_OR_ZERO(desc, G_RA(op));
+ GPR_USED(desc, G_RB(op));
+ FPR_USED(desc, G_RS(op));
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+ return true;
+
+ case 0x2b7: // STFSUX
+ case 0x2f7: // STFDUX
+ if (!(m_context.cap & PPCCAP_FPU))
+ return false;
+ if (G_RA(op) == 0)
+ return false;
+ GPR_USED_OR_ZERO(desc, G_RA(op));
+ GPR_USED(desc, G_RB(op));
+ GPR_MODIFIED(desc, G_RA(op));
+ FPR_USED(desc, G_RS(op));
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+ return true;
+
+ case 0x338: // SRAWIx
+ GPR_USED(desc, G_RS(op));
+ GPR_MODIFIED(desc, G_RA(op));
+ XER_CA_MODIFIED(desc);
+ if (op & M_RC)
+ {
+ XER_SO_USED(desc);
+ CR_MODIFIED(desc, 0);
+ }
+ return true;
+
+ case 0x3f6: // DCBZ
+ if (!(m_context.cap & (PPCCAP_VEA | PPCCAP_4XX)))
+ return false;
+ GPR_USED_OR_ZERO(desc, G_RA(op));
+ GPR_USED(desc, G_RB(op));
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+ return true;
+
+ case 0x106: // ICBT
+ case 0x1c6: // DCCCI
+ case 0x3c6: // ICCCI
+ if (!(m_context.cap & PPCCAP_4XX))
+ return false;
+ GPR_USED_OR_ZERO(desc, G_RA(op));
+ GPR_USED(desc, G_RB(op));
+ desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION;
+ return true;
+
+ case 0x1e6: // DCREAD
+ case 0x3e6: // ICREAD
+ if (!(m_context.cap & PPCCAP_4XX))
+ return false;
+ GPR_USED_OR_ZERO(desc, G_RA(op));
+ GPR_USED(desc, G_RB(op));
+ GPR_MODIFIED(desc, G_RT(op));
+ desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION;
+ return true;
+
+ case 0x143: // MFDCR
+ if (!(m_context.cap & PPCCAP_4XX))
+ return false;
+ GPR_MODIFIED(desc, G_RD(op));
+ desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION;
+ return true;
+
+ case 0x1c3: // MTDCR
+ if (!(m_context.cap & PPCCAP_4XX))
+ return false;
+ GPR_USED(desc, G_RS(op));
+ desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION | OPFLAG_CAN_EXPOSE_EXTERNAL_INT;
+ return true;
+
+ case 0x083: // WRTEE
+ if (!(m_context.cap & PPCCAP_4XX))
+ return false;
+ GPR_USED(desc, G_RS(op));
+ desc.flags |= OPFLAG_CAN_EXPOSE_EXTERNAL_INT;
+ return true;
+
+ case 0x0a3: // WRTEEI
+ if (!(m_context.cap & PPCCAP_4XX))
+ return false;
+ if (op & MSR_EE)
+ desc.flags |= OPFLAG_CAN_EXPOSE_EXTERNAL_INT;
+ return true;
+
+ case 0x254: // ESA
+ case 0x274: // DSA
+ if (!is_602_class())
+ return false;
+ desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION;
+ return true;
+ }
+
+ return false;
+}
+
+
+/*-------------------------------------------------
+ describe_instruction_3b - build a
+ description of a single instruction in the
+ 0x3b group
+-------------------------------------------------*/
+
+bool ppc_frontend::describe_3b(UINT32 op, opcode_desc &desc, const opcode_desc *prev)
+{
+ UINT32 opswitch = (op >> 1) & 0x1f;
+
+ if (!(m_context.cap & PPCCAP_FPU))
+ return false;
+
+ switch (opswitch)
+ {
+ case 0x12: // FDIVSx
+ FPR_USED(desc, G_RA(op));
+ FPR_USED(desc, G_RB(op));
+ FPR_MODIFIED(desc, G_RD(op));
+ if (op & M_RC)
+ CR_MODIFIED(desc, 1);
+ if (is_601_class())
+ desc.cycles = 17; // 601
+ else if (is_603_class())
+ desc.cycles = 18; // 603
+ else
+ desc.cycles = 17; // ???
+ FPSCR_MODIFIED(desc, 4);
+ return true;
+
+ case 0x14: // FSUBSx
+ case 0x15: // FADDSx
+ FPR_USED(desc, G_RA(op));
+ FPR_USED(desc, G_RB(op));
+ FPR_MODIFIED(desc, G_RD(op));
+ if (op & M_RC)
+ CR_MODIFIED(desc, 1);
+ FPSCR_MODIFIED(desc, 4);
+ return true;
+
+ case 0x19: // FMULSx - not the same form as FSUB/FADD!
+ FPR_USED(desc, G_RA(op));
+ FPR_USED(desc, G_REGC(op));
+ FPR_MODIFIED(desc, G_RD(op));
+ if (op & M_RC)
+ CR_MODIFIED(desc, 1);
+ FPSCR_MODIFIED(desc, 4);
+ return true;
+
+ case 0x16: // FSQRTSx
+ case 0x18: // FRESx
+ FPR_USED(desc, G_RB(op));
+ FPR_MODIFIED(desc, G_RD(op));
+ if (op & M_RC)
+ CR_MODIFIED(desc, 1);
+ FPSCR_MODIFIED(desc, 4);
+ return true;
+
+ case 0x1c: // FMSUBSx
+ case 0x1d: // FMADDSx
+ case 0x1e: // FNMSUBSx
+ case 0x1f: // FNMADDSx
+ FPR_USED(desc, G_RA(op));
+ FPR_USED(desc, G_RB(op));
+ FPR_USED(desc, G_REGC(op));
+ FPR_MODIFIED(desc, G_RD(op));
+ if (op & M_RC)
+ CR_MODIFIED(desc, 1);
+ FPSCR_MODIFIED(desc, 4);
+ return true;
+ }
+
+ return false;
+}
+
+
+/*-------------------------------------------------
+ describe_instruction_3f - build a
+ description of a single instruction in the
+ 0x3f group
+-------------------------------------------------*/
+
+bool ppc_frontend::describe_3f(UINT32 op, opcode_desc &desc, const opcode_desc *prev)
+{
+ UINT32 opswitch = (op >> 1) & 0x3ff;
+
+ if (!(m_context.cap & PPCCAP_FPU))
+ return false;
+
+ if (opswitch & 0x10)
+ {
+ opswitch &= 0x1f;
+ switch (opswitch)
+ {
+ case 0x12: // FDIVx
+ FPR_USED(desc, G_RA(op));
+ FPR_USED(desc, G_RB(op));
+ FPR_MODIFIED(desc, G_RD(op));
+ if (op & M_RC)
+ CR_MODIFIED(desc, 1);
+ if (is_601_class())
+ desc.cycles = 31; // 601
+ else if (is_603_class())
+ desc.cycles = 33; // 603
+ else
+ desc.cycles = 31; // ???
+ FPSCR_MODIFIED(desc, 4);
+ return true;
+
+ case 0x19: // FMULx
+ FPR_USED(desc, G_RA(op));
+ FPR_USED(desc, G_REGC(op));
+ FPR_MODIFIED(desc, G_RD(op));
+ if (op & M_RC)
+ CR_MODIFIED(desc, 1);
+ desc.cycles = 2; // 601/603
+ FPSCR_MODIFIED(desc, 4);
+ return true;
+
+ case 0x14: // FSUBx
+ case 0x15: // FADDx
+ FPR_USED(desc, G_RA(op));
+ FPR_USED(desc, G_RB(op));
+ FPR_MODIFIED(desc, G_RD(op));
+ if (op & M_RC)
+ CR_MODIFIED(desc, 1);
+ FPSCR_MODIFIED(desc, 4);
+ return true;
+
+ case 0x16: // FSQRTx
+ case 0x1a: // FSQRTEx
+ FPR_USED(desc, G_RB(op));
+ FPR_MODIFIED(desc, G_RD(op));
+ if (op & M_RC)
+ CR_MODIFIED(desc, 1);
+ FPSCR_MODIFIED(desc, 4);
+ return true;
+
+ case 0x17: // FSELx
+ FPR_USED(desc, G_RA(op));
+ FPR_USED(desc, G_RB(op));
+ FPR_USED(desc, G_REGC(op));
+ FPR_MODIFIED(desc, G_RD(op));
+ if (op & M_RC)
+ CR_MODIFIED(desc, 1);
+ desc.cycles = 2; // 601/603
+ return true;
+
+ case 0x1c: // FMSUBx
+ case 0x1d: // FMADDx
+ case 0x1e: // FNMSUBx
+ case 0x1f: // FNMADDx
+ FPR_USED(desc, G_RA(op));
+ FPR_USED(desc, G_RB(op));
+ FPR_USED(desc, G_REGC(op));
+ FPR_MODIFIED(desc, G_RD(op));
+ if (op & M_RC)
+ CR_MODIFIED(desc, 1);
+ desc.cycles = 2; // 601/603
+ FPSCR_MODIFIED(desc, 4);
+ return true;
+ }
+ }
+ else
+ {
+ switch (opswitch)
+ {
+ case 0x32e: // FCTIDx - 64-bit only
+ case 0x32f: // FCTIDZx - 64-bit only
+ case 0x34e: // FCFIDx - 64-bit only
+ return false;
+
+ case 0x000: // FCMPU
+ case 0x020: // FCMPO
+ FPR_USED(desc, G_RA(op));
+ FPR_USED(desc, G_RB(op));
+ CR_MODIFIED(desc, G_CRFD(op));
+ return true;
+
+ case 0x00c: // FRSPx
+ case 0x00e: // FCTIWx
+ case 0x00f: // FCTIWZx
+ FPSCR_MODIFIED(desc, 4);
+ case 0x028: // FNEGx
+ case 0x048: // FMRx
+ case 0x088: // FNABSx
+ case 0x108: // FABSx
+ FPR_USED(desc, G_RB(op));
+ FPR_MODIFIED(desc, G_RD(op));
+ if (op & M_RC)
+ CR_MODIFIED(desc, 1);
+ return true;
+
+ case 0x026: // MTFSB1x
+ case 0x046: // MTFSB0x
+ FPSCR_MODIFIED(desc, G_CRBD(op) / 4);
+ return true;
+
+ case 0x040: // MCRFS
+ FPSCR_USED(desc, G_CRFS(op));
+ CR_MODIFIED(desc, G_CRFD(op));
+ return true;
+
+ case 0x086: // MTFSFIx
+ FPSCR_MODIFIED(desc, G_CRFD(op));
+ return true;
+
+ case 0x247: // MFFSx
+ FPSCR_USED(desc, 0);
+ FPSCR_USED(desc, 1);
+ FPSCR_USED(desc, 2);
+ FPSCR_USED(desc, 3);
+ FPSCR_USED(desc, 4);
+ FPSCR_USED(desc, 5);
+ FPSCR_USED(desc, 6);
+ FPSCR_USED(desc, 7);
+ FPR_MODIFIED(desc, G_RD(op));
+ return true;
+
+ case 0x2c7: // MTFSFx
+ FPR_USED(desc, G_RB(op));
+ if (G_CRM(op) & 0x80) FPSCR_MODIFIED(desc, 0);
+ if (G_CRM(op) & 0x40) FPSCR_MODIFIED(desc, 1);
+ if (G_CRM(op) & 0x20) FPSCR_MODIFIED(desc, 2);
+ if (G_CRM(op) & 0x10) FPSCR_MODIFIED(desc, 3);
+ if (G_CRM(op) & 0x08) FPSCR_MODIFIED(desc, 4);
+ if (G_CRM(op) & 0x04) FPSCR_MODIFIED(desc, 5);
+ if (G_CRM(op) & 0x02) FPSCR_MODIFIED(desc, 6);
+ if (G_CRM(op) & 0x01) FPSCR_MODIFIED(desc, 7);
+ return true;
+ }
+ }
+
+ return false;
+}