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