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 <cstring>
19 #include "Core/HLE/HLE.h"
20 #include "Core/MemMap.h"
21 #include "Core/MIPS/MIPS.h"
22 #include "Core/MIPS/MIPSCodeUtils.h"
23 #include "Core/MIPS/MIPSDis.h"
24 #include "Core/MIPS/MIPSTables.h"
25 #include "Core/MIPS/MIPSDebugInterface.h"
26 
27 #define _RS   ((op>>21) & 0x1F)
28 #define _RT   ((op>>16) & 0x1F)
29 #define _RD   ((op>>11) & 0x1F)
30 #define _FS   ((op>>11) & 0x1F)
31 #define _FT   ((op>>16) & 0x1F)
32 #define _FD   ((op>>6 ) & 0x1F)
33 #define _POS  ((op>>6 ) & 0x1F)
34 #define _SIZE ((op>>11) & 0x1F)
35 
36 #define RN(i) currentDebugMIPS->GetRegName(0,i)
37 #define FN(i) currentDebugMIPS->GetRegName(1,i)
38 //#define VN(i) currentMIPS->GetRegName(2,i)
39 
40 u32 disPC;
41 
42 namespace MIPSDis
43 {
44 	// One shot, not re-entrant.
SignedHex(int i)45 	const char *SignedHex(int i)
46 	{
47 		static char temp[32];
48 		int offset = 0;
49 		if (i < 0)
50 		{
51 			temp[0] = '-';
52 			offset = 1;
53 			i = -i;
54 		}
55 
56 		sprintf(&temp[offset], "0x%X", i);
57 		return temp;
58 	}
59 
Dis_Generic(MIPSOpcode op,char * out)60 	void Dis_Generic(MIPSOpcode op, char *out)
61 	{
62 		sprintf(out, "%s\t --- unknown ---", MIPSGetName(op));
63 	}
64 
Dis_Cache(MIPSOpcode op,char * out)65 	void Dis_Cache(MIPSOpcode op, char *out)
66 	{
67 		int imm = (s16)(op & 0xFFFF);
68 		int rs = _RS;
69 		int func = (op >> 16) & 0x1F;
70 		sprintf(out, "%s\tfunc=%i, %s(%s)", MIPSGetName(op), func, RN(rs), SignedHex(imm));
71 	}
72 
Dis_mxc1(MIPSOpcode op,char * out)73 	void Dis_mxc1(MIPSOpcode op, char *out)
74 	{
75 		int fs = _FS;
76 		int rt = _RT;
77 		const char *name = MIPSGetName(op);
78 		sprintf(out, "%s\t%s, %s",name,RN(rt),FN(fs));
79 	}
80 
Dis_FPU3op(MIPSOpcode op,char * out)81 	void Dis_FPU3op(MIPSOpcode op, char *out)
82 	{
83 		int ft = _FT;
84 		int fs = _FS;
85 		int fd = _FD;
86 		const char *name = MIPSGetName(op);
87 		sprintf(out, "%s\t%s, %s, %s",name,FN(fd),FN(fs),FN(ft));
88 	}
89 
Dis_FPU2op(MIPSOpcode op,char * out)90 	void Dis_FPU2op(MIPSOpcode op, char *out)
91 	{
92 		int fs = _FS;
93 		int fd = _FD;
94 		const char *name = MIPSGetName(op);
95 		sprintf(out, "%s\t%s, %s",name,FN(fd),FN(fs));
96 	}
97 
Dis_FPULS(MIPSOpcode op,char * out)98 	void Dis_FPULS(MIPSOpcode op, char *out)
99 	{
100 		int offset = (signed short)(op&0xFFFF);
101 		int ft = _FT;
102 		int rs = _RS;
103 		const char *name = MIPSGetName(op);
104 		sprintf(out, "%s\t%s, %s(%s)",name,FN(ft),SignedHex(offset),RN(rs));
105 	}
Dis_FPUComp(MIPSOpcode op,char * out)106 	void Dis_FPUComp(MIPSOpcode op, char *out)
107 	{
108 		int fs = _FS;
109 		int ft = _FT;
110 		const char *name = MIPSGetName(op);
111 		sprintf(out, "%s\t%s, %s",name,FN(fs),FN(ft));
112 	}
113 
Dis_FPUBranch(MIPSOpcode op,char * out)114 	void Dis_FPUBranch(MIPSOpcode op, char *out)
115 	{
116 		u32 off = disPC;
117 		int imm = (signed short)(op&0xFFFF)<<2;
118 		off += imm + 4;
119 		const char *name = MIPSGetName(op);
120 		sprintf(out, "%s\t->$%08x",name,off);
121 	}
122 
Dis_RelBranch(MIPSOpcode op,char * out)123 	void Dis_RelBranch(MIPSOpcode op, char *out)
124 	{
125 		u32 off = disPC;
126 		int imm = (signed short)(op&0xFFFF)<<2;
127 		int rs = _RS;
128 		off += imm + 4;
129 
130 		const char *name = MIPSGetName(op);
131 		sprintf(out, "%s\t%s, ->$%08x", name, RN(rs), off);
132 	}
133 
Dis_Syscall(MIPSOpcode op,char * out)134 	void Dis_Syscall(MIPSOpcode op, char *out)
135 	{
136 		u32 callno = (op>>6) & 0xFFFFF; //20 bits
137 		int funcnum = callno & 0xFFF;
138 		int modulenum = (callno & 0xFF000) >> 12;
139 		sprintf(out, "syscall\t	%s",/*PSPHLE::GetModuleName(modulenum),*/GetFuncName(modulenum, funcnum));
140 	}
141 
Dis_ToHiloTransfer(MIPSOpcode op,char * out)142 	void Dis_ToHiloTransfer(MIPSOpcode op, char *out)
143 	{
144 		int rs = _RS;
145 		const char *name = MIPSGetName(op);
146 		sprintf(out, "%s\t%s",name,RN(rs));
147 	}
Dis_FromHiloTransfer(MIPSOpcode op,char * out)148 	void Dis_FromHiloTransfer(MIPSOpcode op, char *out)
149 	{
150 		int rd = _RD;
151 		const char *name = MIPSGetName(op);
152 		sprintf(out, "%s\t%s",name,RN(rd));
153 	}
154 
Dis_RelBranch2(MIPSOpcode op,char * out)155 	void Dis_RelBranch2(MIPSOpcode op, char *out)
156 	{
157 		u32 off = disPC;
158 		int imm = (signed short)(op&0xFFFF)<<2;
159 		int rt = _RT;
160 		int rs = _RS;
161 		off += imm + 4;
162 
163 		const char *name = MIPSGetName(op);
164 		int o = op>>26;
165 		if (o==4 && rs == rt)//beq
166 			sprintf(out, "b\t->$%08x", off);
167 		else if (o==20 && rs == rt)//beql
168 			sprintf(out, "bl\t->$%08x", off);
169 		else
170 			sprintf(out, "%s\t%s, %s, ->$%08x", name, RN(rs), RN(rt), off);
171 	}
172 
Dis_IType(MIPSOpcode op,char * out)173 	void Dis_IType(MIPSOpcode op, char *out)
174 	{
175 		u32 uimm = op & 0xFFFF;
176 		u32 suimm = SignExtend16ToU32(op);
177 		s32 simm = SignExtend16ToS32(op);
178 
179 		int rt = _RT;
180 		int rs = _RS;
181 		const char *name = MIPSGetName(op);
182 		switch (op >> 26)
183 		{
184 		case 8: //addi
185 		case 9: //addiu
186 		case 10: //slti
187 			sprintf(out, "%s\t%s, %s, %s",name,RN(rt),RN(rs),SignedHex(simm));
188 			break;
189 		case 11: //sltiu
190 			sprintf(out, "%s\t%s, %s, 0x%X",name,RN(rt),RN(rs),suimm);
191 			break;
192 		default:
193 			sprintf(out, "%s\t%s, %s, 0x%X",name,RN(rt),RN(rs),uimm);
194 			break;
195 		}
196 	}
Dis_ori(MIPSOpcode op,char * out)197 	void Dis_ori(MIPSOpcode op, char *out)
198 	{
199 		u32 uimm = (u32)(u16)(op & 0xFFFF);
200 		int rt = _RT;
201 		int rs = _RS;
202 		const char *name = MIPSGetName(op);
203 		if (rs == 0)
204 			sprintf(out, "li\t%s, 0x%X",RN(rt),uimm);
205 		else
206 			sprintf(out, "%s\t%s, %s, 0x%X",name,RN(rt),RN(rs),uimm);
207 	}
208 
Dis_IType1(MIPSOpcode op,char * out)209 	void Dis_IType1(MIPSOpcode op, char *out)
210 	{
211 		u32 uimm = (u32)(u16)(op & 0xFFFF);
212 		int rt = _RT;
213 		const char *name = MIPSGetName(op);
214 		sprintf(out, "%s\t%s, 0x%X",name,RN(rt),uimm);
215 	}
216 
Dis_addi(MIPSOpcode op,char * out)217 	void Dis_addi(MIPSOpcode op, char *out)
218 	{
219 		int imm = (signed short)(op&0xFFFF);
220 		int rt = _RT;
221 		int rs = _RS;
222 		if (rs == 0)
223 			sprintf(out, "li\t%s, %s",RN(rt),SignedHex(imm));
224 		else
225 			Dis_IType(op,out);
226 	}
227 
Dis_ITypeMem(MIPSOpcode op,char * out)228 	void Dis_ITypeMem(MIPSOpcode op, char *out)
229 	{
230 		int imm = (signed short)(op&0xFFFF);
231 		int rt = _RT;
232 		int rs = _RS;
233 		const char *name = MIPSGetName(op);
234 		sprintf(out, "%s\t%s, %s(%s)",name,RN(rt),SignedHex(imm),RN(rs));
235 	}
236 
Dis_RType2(MIPSOpcode op,char * out)237 	void Dis_RType2(MIPSOpcode op, char *out)
238 	{
239 		int rs = _RS;
240 		int rd = _RD;
241 		const char *name = MIPSGetName(op);
242 		sprintf(out, "%s\t%s, %s",name,RN(rd),RN(rs));
243 	}
244 
Dis_RType3(MIPSOpcode op,char * out)245 	void Dis_RType3(MIPSOpcode op, char *out)
246 	{
247 		int rt = _RT;
248 		int rs = _RS;
249 		int rd = _RD;
250 		const char *name = MIPSGetName(op);
251 		sprintf(out, "%s\t%s, %s, %s",name,RN(rd),RN(rs),RN(rt));
252 	}
253 
Dis_addu(MIPSOpcode op,char * out)254 	void Dis_addu(MIPSOpcode op, char *out)
255 	{
256 		int rt = _RT;
257 		int rs = _RS;
258 		int rd = _RD;
259 		const char *name = MIPSGetName(op);
260 		if (rs==0 && rt==0)
261 			sprintf(out,"li\t%s, 0",RN(rd));
262 		else if (rs == 0)
263 			sprintf(out,"move\t%s, %s",RN(rd),RN(rt));
264 		else if (rt == 0)
265 			sprintf(out,"move\t%s, %s",RN(rd),RN(rs));
266 		else
267 			sprintf(out, "%s\t%s, %s, %s",name,RN(rd),RN(rs),RN(rt));
268 	}
269 
Dis_ShiftType(MIPSOpcode op,char * out)270 	void Dis_ShiftType(MIPSOpcode op, char *out)
271 	{
272 		int rt = _RT;
273 		int rs = _RS;
274 		int rd = _RD;
275 		int sa = (op>>6)	& 0x1F;
276 		const char *name = MIPSGetName(op);
277 		if (((op & 0x3f) == 2) && rs == 1)
278 			name = "rotr";
279 		if (((op & 0x3f) == 6) && sa == 1)
280 			name = "rotrv";
281 		sprintf(out, "%s\t%s, %s, 0x%X",name,RN(rd),RN(rt),sa);
282 	}
283 
Dis_VarShiftType(MIPSOpcode op,char * out)284 	void Dis_VarShiftType(MIPSOpcode op, char *out)
285 	{
286 		int rt = _RT;
287 		int rs = _RS;
288 		int rd = _RD;
289 		int sa = (op>>6)	& 0x1F;
290 		const char *name = MIPSGetName(op);
291 		if (((op & 0x3f) == 6) && sa == 1)
292 			name = "rotrv";
293 		sprintf(out, "%s\t%s, %s, %s",name,RN(rd),RN(rt),RN(rs));
294 	}
295 
296 
Dis_MulDivType(MIPSOpcode op,char * out)297 	void Dis_MulDivType(MIPSOpcode op, char *out)
298 	{
299 		int rt = _RT;
300 		int rs = _RS;
301 		const char *name = MIPSGetName(op);
302 		sprintf(out, "%s\t%s, %s",name,RN(rs),RN(rt));
303 	}
304 
305 
Dis_Special3(MIPSOpcode op,char * out)306 	void Dis_Special3(MIPSOpcode op, char *out)
307 	{
308 		int rs = _RS;
309 		int Rt = _RT;
310 		int pos = _POS;
311 		const char *name = MIPSGetName(op);
312 
313 		switch (op & 0x3f)
314 		{
315 		case 0x0: //ext
316 			{
317 				int size = _SIZE + 1;
318 				sprintf(out,"%s\t%s, %s, 0x%X, 0x%X",name,RN(Rt),RN(rs),pos,size);
319 			}
320 			break;
321 		case 0x4: // ins
322 			{
323 				int size = (_SIZE + 1) - pos;
324 				sprintf(out,"%s\t%s, %s, 0x%X, 0x%X",name,RN(Rt),RN(rs),pos,size);
325 			}
326 			break;
327 		}
328 	}
329 
Dis_JumpType(MIPSOpcode op,char * out)330 	void Dis_JumpType(MIPSOpcode op, char *out)
331 	{
332 		u32 off = ((op & 0x03FFFFFF) << 2);
333 		u32 addr = (disPC & 0xF0000000) | off;
334 		const char *name = MIPSGetName(op);
335 		sprintf(out, "%s\t->$%08x",name,addr);
336 	}
337 
Dis_JumpRegType(MIPSOpcode op,char * out)338 	void Dis_JumpRegType(MIPSOpcode op, char *out)
339 	{
340 		int rs = _RS;
341 		int rd = _RD;
342 		const char *name = MIPSGetName(op);
343 		if ((op & 0x3f) == 9 && rd != MIPS_REG_RA)
344 			sprintf(out, "%s\t%s,->%s", name, RN(rd), RN(rs));
345 		else
346 			sprintf(out, "%s\t->%s", name, RN(rs));
347 	}
348 
Dis_Allegrex(MIPSOpcode op,char * out)349 	void Dis_Allegrex(MIPSOpcode op, char *out)
350 	{
351 		int rt = _RT;
352 		int rd = _RD;
353 		const char *name = MIPSGetName(op);
354 		sprintf(out,"%s\t%s,%s",name,RN(rd),RN(rt));
355 	}
356 
Dis_Allegrex2(MIPSOpcode op,char * out)357 	void Dis_Allegrex2(MIPSOpcode op, char *out)
358 	{
359 		int rt = _RT;
360 		int rd = _RD;
361 		const char *name = MIPSGetName(op);
362 		sprintf(out,"%s\t%s,%s",name,RN(rd),RN(rt));
363 	}
364 
Dis_Emuhack(MIPSOpcode op,char * out)365 	void Dis_Emuhack(MIPSOpcode op, char *out)
366 	{
367 		auto resolved = Memory::Read_Instruction(disPC, true);
368 		char disasm[256];
369 		if (MIPS_IS_EMUHACK(resolved)) {
370 			strcpy(disasm, "(invalid emuhack)");
371 		} else {
372 			MIPSDisAsm(resolved, disPC, disasm, true);
373 		}
374 
375 		switch (op.encoding >> 24) {
376 		case 0x68:
377 			snprintf(out, 256, "* jitblock: %s", disasm);
378 			break;
379 		case 0x6a:
380 			snprintf(out, 256, "* replacement: %s", disasm);
381 			break;
382 		default:
383 			snprintf(out, 256, "* (invalid): %s", disasm);
384 			break;
385 		}
386 	}
387 
388 
389 }
390