diff options
Diffstat (limited to 'trunk/src/emu/cpu/powerpc/ppcfe.c')
-rw-r--r-- | trunk/src/emu/cpu/powerpc/ppcfe.c | 1422 |
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; +} |