/*************************************************************************** rspfe.c Front-end for RSP recompiler Copyright the MESS team Released for general non-commercial use under the MAME license Visit http://mamedev.org for licensing and usage restrictions. ***************************************************************************/ #include "emu.h" #include "rspfe.h" #include "rsp.h" //************************************************************************** // RSP FRONTEND //************************************************************************** //------------------------------------------------- // rsp_frontend - constructor //------------------------------------------------- rsp_frontend::rsp_frontend(rsp_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 rsp_frontend::describe(opcode_desc &desc, const opcode_desc *prev) { UINT32 op, opswitch; // fetch the opcode op = desc.opptr.l[0] = m_context.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 << 2)) & 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 << 2)) & 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; } //------------------------------------------------- // describe_special - build a description of a // single instruction in the 'special' group //------------------------------------------------- bool rsp_frontend::describe_special(UINT32 op, opcode_desc &desc) { switch (op & 63) { case 0x00: // SLL case 0x02: // SRL case 0x03: // SRA desc.regin[0] |= REGFLAG_R(RTREG); desc.regout[0] |= REGFLAG_R(RDREG); return true; case 0x04: // SLLV case 0x06: // SRLV case 0x07: // SRAV case 0x21: // ADDU case 0x23: // SUBU case 0x24: // AND case 0x25: // OR case 0x26: // XOR case 0x27: // NOR case 0x2a: // SLT case 0x2b: // SLTU desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); desc.regout[0] |= REGFLAG_R(RDREG); return true; case 0x20: // ADD case 0x22: // SUB desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); desc.regout[0] |= REGFLAG_R(RDREG); return true; case 0x08: // JR desc.regin[0] |= REGFLAG_R(RSREG); desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; desc.targetpc = BRANCH_TARGET_DYNAMIC; desc.delayslots = 1; return true; case 0x09: // JALR desc.regin[0] |= REGFLAG_R(RSREG); desc.regout[0] |= REGFLAG_R(RDREG); desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; desc.targetpc = BRANCH_TARGET_DYNAMIC; desc.delayslots = 1; return true; case 0x0d: // BREAK desc.flags |= OPFLAG_END_SEQUENCE; desc.targetpc = BRANCH_TARGET_DYNAMIC; return true; } return false; } //------------------------------------------------- // describe_regimm - build a description of a // single instruction in the 'regimm' group //------------------------------------------------- bool rsp_frontend::describe_regimm(UINT32 op, opcode_desc &desc) { switch (RTREG) { case 0x00: // BLTZ case 0x01: // BGEZ if (RTREG == 0x01 && 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)) & 0x00000fff) | 0x1000; desc.delayslots = 1; desc.skipslots = (RTREG & 0x02) ? 1 : 0; return true; case 0x10: // BLTZAL case 0x11: // BGEZAL if (RTREG == 0x11 && 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.regout[0] |= REGFLAG_R(31); desc.targetpc = ((desc.pc + 4 + (SIMMVAL << 2)) & 0x00000fff) | 0x1000; desc.delayslots = 1; desc.skipslots = (RTREG & 0x02) ? 1 : 0; return true; } return false; } //------------------------------------------------- // describe_cop0 - build a description of a // single instruction in the COP0 group //------------------------------------------------- bool rsp_frontend::describe_cop0(UINT32 op, opcode_desc &desc) { switch (RSREG) { case 0x00: // MFCz desc.regout[0] |= REGFLAG_R(RTREG); return true; case 0x04: // MTCz desc.regin[0] |= REGFLAG_R(RTREG); if(RDREG == 2) // SP_RD_LEN, initiating DMA { desc.flags |= OPFLAG_END_SEQUENCE; } return true; } return false; } //------------------------------------------------- // describe_cop2 - build a description of a // single instruction in the COP2 group //------------------------------------------------- bool rsp_frontend::describe_cop2(UINT32 op, opcode_desc &desc) { switch (RSREG) { case 0x00: // MFCz case 0x02: // CFCz desc.regout[0] |= REGFLAG_R(RTREG); return true; case 0x04: // MTCz case 0x06: // CTCz desc.regin[0] |= REGFLAG_R(RTREG); return true; } return false; }