bool rsp_frontend::describe(opcode_desc &desc, const opcode_desc *prev) { UINT32 op, opswitch; // fetch the opcode op = desc.opptr.l[0] = m_rsp.m_direct->read_decrypted_dword(desc.physpc | 0x1000); // 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 0x00: // SPECIAL return describe_special(op, desc); case 0x01: // REGIMM return describe_regimm(op, desc); case 0x10: // COP0 return describe_cop0(op, desc); case 0x12: // COP2 return describe_cop2(op, desc); case 0x02: // J desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; desc.targetpc = ((LIMMVAL << 2) & 0x00000fff) | 0x1000; desc.delayslots = 1; return true; case 0x03: // JAL desc.regout[0] |= REGFLAG_R(31); desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; desc.targetpc = ((LIMMVAL << 2) & 0x00000fff) | 0x1000; desc.delayslots = 1; return true; case 0x04: // BEQ case 0x05: // BNE if ((opswitch == 0x04 || opswitch == 0x14) && RSREG == RTREG) desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; else { desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; } desc.targetpc = ((desc.pc + 4 + SIMMVAL * 4) & 0x00000fff) | 0x1000; desc.delayslots = 1; desc.skipslots = (opswitch & 0x10) ? 1 : 0; return true; case 0x06: // BLEZ case 0x07: // BGTZ if ((opswitch == 0x06 || opswitch == 0x16) && RSREG == 0) desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; else { desc.regin[0] |= REGFLAG_R(RSREG); desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; } desc.targetpc = ((desc.pc + 4 + SIMMVAL * 4) & 0x00000fff) | 0x1000; desc.delayslots = 1; desc.skipslots = (opswitch & 0x10) ? 1 : 0; return true; case 0x08: // ADDI desc.regin[0] |= REGFLAG_R(RSREG); desc.regout[0] |= REGFLAG_R(RTREG); return true; case 0x09: // ADDIU case 0x0a: // SLTI case 0x0b: // SLTIU case 0x0c: // ANDI case 0x0d: // ORI case 0x0e: // XORI desc.regin[0] |= REGFLAG_R(RSREG); desc.regout[0] |= REGFLAG_R(RTREG); return true; case 0x0f: // LUI desc.regout[0] |= REGFLAG_R(RTREG); return true; case 0x20: // LB case 0x21: // LH case 0x23: // LW case 0x24: // LBU case 0x25: // LHU case 0x27: // LWU desc.regin[0] |= REGFLAG_R(RSREG); desc.regout[0] |= REGFLAG_R(RTREG); desc.flags |= OPFLAG_READS_MEMORY; return true; case 0x28: // SB case 0x29: // SH case 0x2b: // SW desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); desc.flags |= OPFLAG_WRITES_MEMORY; return true; case 0x32: // LWC2 desc.regin[0] |= REGFLAG_R(RSREG); desc.flags |= OPFLAG_READS_MEMORY; return true; case 0x3a: // SWC2 desc.regin[0] |= REGFLAG_R(RSREG); desc.flags |= OPFLAG_WRITES_MEMORY; return true; } return false; }
bool mips3_frontend::describe(opcode_desc &desc, const opcode_desc *prev) { UINT32 op, opswitch; // compute the physical PC assert((desc.physpc & 3) == 0); if (!mips3com_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 assert((desc.physpc & 3) == 0); op = desc.opptr.l[0] = m_context.direct->read_decrypted_dword(desc.physpc); // 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 0x00: // SPECIAL return describe_special(op, desc); case 0x01: // REGIMM return describe_regimm(op, desc); case 0x10: // COP0 return describe_cop0(op, desc); case 0x11: // COP1 return describe_cop1(op, desc); case 0x12: // COP2 return describe_cop2(op, desc); case 0x13: // COP1X - MIPS IV if (m_context.flavor < MIPS3_TYPE_MIPS_IV) return false; return describe_cop1x(op, desc); case 0x1c: // IDT-specific opcodes: mad/madu/mul on R4640/4650, msub on RC32364 return describe_idt(op, desc); case 0x02: // J desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; desc.targetpc = (desc.pc & 0xf0000000) | (LIMMVAL << 2); desc.delayslots = 1; return true; case 0x03: // JAL desc.regout[0] |= REGFLAG_R(31); desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; desc.targetpc = (desc.pc & 0xf0000000) | (LIMMVAL << 2); desc.delayslots = 1; return true; case 0x04: // BEQ case 0x05: // BNE case 0x14: // BEQL case 0x15: // BNEL if ((opswitch == 0x04 || opswitch == 0x14) && RSREG == RTREG) desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; else { desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; } desc.targetpc = desc.pc + 4 + (SIMMVAL << 2); desc.delayslots = 1; desc.skipslots = (opswitch & 0x10) ? 1 : 0; return true; case 0x06: // BLEZ case 0x07: // BGTZ case 0x16: // BLEZL case 0x17: // BGTZL if ((opswitch == 0x06 || opswitch == 0x16) && RSREG == 0) desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; else { desc.regin[0] |= REGFLAG_R(RSREG); desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; } desc.targetpc = desc.pc + 4 + (SIMMVAL << 2); desc.delayslots = 1; desc.skipslots = (opswitch & 0x10) ? 1 : 0; return true; case 0x08: // ADDI case 0x18: // DADDI desc.regin[0] |= REGFLAG_R(RSREG); desc.regout[0] |= REGFLAG_R(RTREG); desc.flags |= OPFLAG_CAN_CAUSE_EXCEPTION; return true; case 0x09: // ADDIU case 0x0a: // SLTI case 0x0b: // SLTIU case 0x0c: // ANDI case 0x0d: // ORI case 0x0e: // XORI case 0x19: // DADDIU desc.regin[0] |= REGFLAG_R(RSREG); desc.regout[0] |= REGFLAG_R(RTREG); return true; case 0x0f: // LUI desc.regout[0] |= REGFLAG_R(RTREG); return true; case 0x1a: // LDL case 0x1b: // LDR case 0x22: // LWL case 0x26: // LWR desc.regin[0] |= REGFLAG_R(RTREG); case 0x20: // LB case 0x21: // LH case 0x23: // LW case 0x24: // LBU case 0x25: // LHU case 0x27: // LWU case 0x30: // LL case 0x34: // LLD case 0x37: // LD desc.regin[0] |= REGFLAG_R(RSREG); desc.regout[0] |= REGFLAG_R(RTREG); desc.flags |= OPFLAG_READS_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION; return true; case 0x28: // SB case 0x29: // SH case 0x2a: // SWL case 0x2b: // SW case 0x2c: // SDL case 0x2d: // SDR case 0x2e: // SWR case 0x3f: // SD desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); desc.flags |= OPFLAG_WRITES_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION; return true; case 0x38: // SC case 0x3c: // SCD desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); desc.regout[0] |= REGFLAG_R(RTREG); desc.flags |= OPFLAG_WRITES_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION; return true; case 0x31: // LWC1 case 0x35: // LDC1 desc.regin[0] |= REGFLAG_R(RSREG); desc.regout[1] |= REGFLAG_CPR1(RTREG); desc.flags |= OPFLAG_READS_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION; return true; case 0x39: // SWC1 case 0x3d: // SDC1 desc.regin[0] |= REGFLAG_R(RSREG); desc.regin[1] |= REGFLAG_CPR1(RTREG); desc.flags |= OPFLAG_WRITES_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION; return true; case 0x32: // LWC2 case 0x36: // LDC2 desc.regin[0] |= REGFLAG_R(RSREG); desc.flags |= OPFLAG_READS_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION; return true; case 0x3a: // SWC2 case 0x3e: // SDC2 desc.regin[0] |= REGFLAG_R(RSREG); desc.flags |= OPFLAG_WRITES_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION; return true; case 0x33: // PREF if (m_context.flavor < MIPS3_TYPE_MIPS_IV) return false; case 0x2f: // CACHE // effective no-op return true; } return false; }