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; }
int ppcfe_describe(void *param, opcode_desc *desc, const opcode_desc *prev) { powerpc_state *ppc = (powerpc_state *)param; UINT32 op, opswitch; int regnum; /* compute the physical PC */ if (!ppccom_translate_address(ppc, ADDRESS_SPACE_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] = ppc->direct->read_decrypted_dword(desc->physpc, ppc->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(ppc)) 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(ppc)) desc->cycles = 4; /* 4XX */ else if (is_601_class(ppc)) desc->cycles = 5; /* 601 */ else if (is_603_class(ppc)) 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 (!(ppc->cap & (PPCCAP_OEA | PPCCAP_4XX))) return FALSE; desc->flags |= OPFLAG_WILL_CAUSE_EXCEPTION; if (is_601_class(ppc)) desc->cycles = 16; /* 601 */ else if (is_603_class(ppc)) 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_instruction_13(ppc, 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_instruction_1f(ppc, 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 (!(ppc->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 (!(ppc->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 (!(ppc->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 (!(ppc->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_instruction_3b(ppc, op, desc, prev); case 0x3f: /* 0x3f group */ return describe_instruction_3f(ppc, op, desc, prev); } return FALSE; }