1 // Copyright (c) 2012- PPSSPP Project. 2 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU General Public License as published by 5 // the Free Software Foundation, version 2.0 or later versions. 6 7 // This program is distributed in the hope that it will be useful, 8 // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 // GNU General Public License 2.0 for more details. 11 12 // A copy of the GPL 2.0 should have been included with the program. 13 // If not, see http://www.gnu.org/licenses/ 14 15 // Official git repository and contact information can be found at 16 // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. 17 18 #include "Core/MIPS/MIPS.h" 19 #include "Core/MIPS/MIPSTables.h" 20 #include "Core/MIPS/MIPSCodeUtils.h" 21 #include "Core/Host.h" 22 #include "Core/MemMap.h" 23 24 namespace MIPSCodeUtils 25 { 26 27 #define OP_SYSCALL 0x0000000c 28 #define OP_SYSCALL_MASK 0xFC00003F 29 #define _RS ((op>>21) & 0x1F) 30 #define _RT ((op>>16) & 0x1F) 31 #define _IMM26 (op & 0x03FFFFFF) 32 #define TARGET16 ((int)(SignExtend16ToU32(op) << 2)) 33 #define TARGET26 (_IMM26 << 2) 34 GetJumpTarget(u32 addr)35 u32 GetJumpTarget(u32 addr) { 36 MIPSOpcode op = Memory::Read_Instruction(addr, true); 37 if (op != 0) { 38 MIPSInfo info = MIPSGetInfo(op); 39 if ((info & IS_JUMP) && (info & IN_IMM26)) 40 return (addr & 0xF0000000) | TARGET26; 41 else 42 return INVALIDTARGET; 43 } else { 44 return INVALIDTARGET; 45 } 46 } 47 GetBranchTarget(u32 addr)48 u32 GetBranchTarget(u32 addr) { 49 MIPSOpcode op = Memory::Read_Instruction(addr, true); 50 if (op != 0) { 51 MIPSInfo info = MIPSGetInfo(op); 52 if (info & IS_CONDBRANCH) 53 return addr + 4 + TARGET16; 54 else 55 return INVALIDTARGET; 56 } else { 57 return INVALIDTARGET; 58 } 59 } 60 GetBranchTargetNoRA(u32 addr)61 u32 GetBranchTargetNoRA(u32 addr) { 62 MIPSOpcode op = Memory::Read_Instruction(addr, true); 63 return GetBranchTargetNoRA(addr, op); 64 } 65 GetBranchTargetNoRA(u32 addr,MIPSOpcode op)66 u32 GetBranchTargetNoRA(u32 addr, MIPSOpcode op) { 67 if (op != 0) { 68 MIPSInfo info = MIPSGetInfo(op); 69 if ((info & IS_CONDBRANCH) && !(info & OUT_RA)) 70 return addr + 4 + TARGET16; 71 else 72 return INVALIDTARGET; 73 } else { 74 return INVALIDTARGET; 75 } 76 } 77 GetSureBranchTarget(u32 addr)78 u32 GetSureBranchTarget(u32 addr) { 79 MIPSOpcode op = Memory::Read_Instruction(addr, true); 80 if (op != 0) { 81 MIPSInfo info = MIPSGetInfo(op); 82 if ((info & IS_CONDBRANCH) && !(info & (IN_FPUFLAG | IS_VFPU))) { 83 bool sure; 84 bool takeBranch; 85 switch (info & CONDTYPE_MASK) 86 { 87 case CONDTYPE_EQ: 88 sure = _RS == _RT; 89 takeBranch = true; 90 break; 91 92 case CONDTYPE_NE: 93 sure = _RS == _RT; 94 takeBranch = false; 95 break; 96 97 case CONDTYPE_LEZ: 98 case CONDTYPE_GEZ: 99 sure = _RS == 0; 100 takeBranch = true; 101 break; 102 103 case CONDTYPE_LTZ: 104 case CONDTYPE_GTZ: 105 sure = _RS == 0; 106 takeBranch = false; 107 break; 108 109 default: 110 sure = false; 111 } 112 113 if (sure && takeBranch) 114 return addr + 4 + TARGET16; 115 else if (sure && !takeBranch) 116 return addr + 8; 117 else 118 return INVALIDTARGET; 119 } else { 120 return INVALIDTARGET; 121 } 122 } else { 123 return INVALIDTARGET; 124 } 125 } 126 IsVFPUBranch(MIPSOpcode op)127 bool IsVFPUBranch(MIPSOpcode op) { 128 return (MIPSGetInfo(op) & (IS_VFPU | IS_CONDBRANCH)) == (IS_VFPU | IS_CONDBRANCH); 129 } 130 IsBranch(MIPSOpcode op)131 bool IsBranch(MIPSOpcode op) { 132 return (MIPSGetInfo(op) & IS_CONDBRANCH) == IS_CONDBRANCH; 133 } 134 135 136 } 137