1 #include "Common/CommonFuncs.h"
2 #include "Core/MIPS/IR/IRInst.h"
3 #include "Core/MIPS/IR/IRPassSimplify.h"
4 #include "Core/MIPS/MIPSDebugInterface.h"
5 
6 // Legend
7 // ======================
8 //  _ = ignore
9 //  G = GPR register
10 //  C = 32-bit constant from array
11 //  I = immediate value from instruction
12 //  F = FPR register, single
13 //  V = FPR register, Vec4. Reg number always divisible by 4.
14 //  2 = FPR register, Vec2 (uncommon)
15 //  v = Vec4Init constant, chosen by immediate
16 //  s = Shuffle immediate (4 2-bit fields, choosing a xyzw shuffle)
17 
18 static const IRMeta irMeta[] = {
19 	{ IROp::Nop, "Nop", "" },
20 	{ IROp::SetConst, "SetConst", "GC" },
21 	{ IROp::SetConstF, "SetConstF", "FC" },
22 	{ IROp::Mov, "Mov", "GG" },
23 	{ IROp::Add, "Add", "GGG" },
24 	{ IROp::Sub, "Sub", "GGG" },
25 	{ IROp::Neg, "Neg", "GG" },
26 	{ IROp::Not, "Not", "GG" },
27 	{ IROp::And, "And", "GGG" },
28 	{ IROp::Or, "Or", "GGG" },
29 	{ IROp::Xor, "Xor", "GGG" },
30 	{ IROp::AddConst, "AddConst", "GGC" },
31 	{ IROp::SubConst, "SubConst", "GGC" },
32 	{ IROp::AndConst, "AndConst", "GGC" },
33 	{ IROp::OrConst, "OrConst", "GGC" },
34 	{ IROp::XorConst, "XorConst", "GGC" },
35 	{ IROp::Shl, "Shl", "GGG" },
36 	{ IROp::Shr, "Shr", "GGG" },
37 	{ IROp::Sar, "Sar", "GGG" },
38 	{ IROp::Ror, "Ror", "GGG" },
39 	{ IROp::ShlImm, "ShlImm", "GGI" },
40 	{ IROp::ShrImm, "ShrImm", "GGI" },
41 	{ IROp::SarImm, "SarImm", "GGI" },
42 	{ IROp::RorImm, "RorImm", "GGI" },
43 	{ IROp::Slt, "Slt", "GGG" },
44 	{ IROp::SltConst, "SltConst", "GGC" },
45 	{ IROp::SltU, "SltU", "GGG" },
46 	{ IROp::SltUConst, "SltUConst", "GGC" },
47 	{ IROp::Clz, "Clz", "GG" },
48 	{ IROp::MovZ, "MovZ", "GGG", IRFLAG_SRC3DST },
49 	{ IROp::MovNZ, "MovNZ", "GGG", IRFLAG_SRC3DST },
50 	{ IROp::Max, "Max", "GGG" },
51 	{ IROp::Min, "Min", "GGG" },
52 	{ IROp::BSwap16, "BSwap16", "GG" },
53 	{ IROp::BSwap32, "BSwap32", "GG" },
54 	{ IROp::Mult, "Mult", "_GG" },
55 	{ IROp::MultU, "MultU", "_GG" },
56 	{ IROp::Madd, "Madd", "_GG" },
57 	{ IROp::MaddU, "MaddU", "_GG" },
58 	{ IROp::Msub, "Msub", "_GG" },
59 	{ IROp::MsubU, "MsubU", "_GG" },
60 	{ IROp::Div, "Div", "_GG" },
61 	{ IROp::DivU, "DivU", "_GG" },
62 	{ IROp::MtLo, "MtLo", "_G" },
63 	{ IROp::MtHi, "MtHi", "_G" },
64 	{ IROp::MfLo, "MfLo", "G" },
65 	{ IROp::MfHi, "MfHi", "G" },
66 	{ IROp::Ext8to32, "Ext8to32", "GG" },
67 	{ IROp::Ext16to32, "Ext16to32", "GG" },
68 	{ IROp::ReverseBits, "ReverseBits", "GG" },
69 	{ IROp::Load8, "Load8", "GGC" },
70 	{ IROp::Load8Ext, "Load8", "GGC" },
71 	{ IROp::Load16, "Load16", "GGC" },
72 	{ IROp::Load16Ext, "Load16Ext", "GGC" },
73 	{ IROp::Load32, "Load32", "GGC" },
74 	{ IROp::Load32Left, "Load32Left", "GGC", IRFLAG_SRC3DST },
75 	{ IROp::Load32Right, "Load32Right", "GGC", IRFLAG_SRC3DST },
76 	{ IROp::LoadFloat, "LoadFloat", "FGC" },
77 	{ IROp::LoadVec4, "LoadVec4", "VGC" },
78 	{ IROp::Store8, "Store8", "GGC", IRFLAG_SRC3 },
79 	{ IROp::Store16, "Store16", "GGC", IRFLAG_SRC3 },
80 	{ IROp::Store32, "Store32", "GGC", IRFLAG_SRC3 },
81 	{ IROp::Store32Left, "Store32Left", "GGC", IRFLAG_SRC3 },
82 	{ IROp::Store32Right, "Store32Right", "GGC", IRFLAG_SRC3 },
83 	{ IROp::StoreFloat, "StoreFloat", "FGC", IRFLAG_SRC3 },
84 	{ IROp::StoreVec4, "StoreVec4", "VGC", IRFLAG_SRC3 },
85 	{ IROp::FAdd, "FAdd", "FFF" },
86 	{ IROp::FSub, "FSub", "FFF" },
87 	{ IROp::FMul, "FMul", "FFF" },
88 	{ IROp::FDiv, "FDiv", "FFF" },
89 	{ IROp::FMin, "FMin", "FFF" },
90 	{ IROp::FMax, "FMax", "FFF" },
91 	{ IROp::FMov, "FMov", "FF" },
92 	{ IROp::FSqrt, "FSqrt", "FF" },
93 	{ IROp::FSin, "FSin", "FF" },
94 	{ IROp::FCos, "FCos", "FF" },
95 	{ IROp::FSqrt, "FSqrt", "FF" },
96 	{ IROp::FRSqrt, "FRSqrt", "FF" },
97 	{ IROp::FRecip, "FRecip", "FF" },
98 	{ IROp::FAsin, "FAsin", "FF" },
99 	{ IROp::FNeg, "FNeg", "FF" },
100 	{ IROp::FSign, "FSign", "FF" },
101 	{ IROp::FAbs, "FAbs", "FF" },
102 	{ IROp::FRound, "FRound", "FF" },
103 	{ IROp::FTrunc, "FTrunc", "FF" },
104 	{ IROp::FCeil, "FCeil", "FF" },
105 	{ IROp::FFloor, "FFloor", "FF" },
106 	{ IROp::FCvtWS, "FCvtWS", "FF" },
107 	{ IROp::FCvtSW, "FCvtSW", "FF" },
108 	{ IROp::FCmp, "FCmp", "mFF" },
109 	{ IROp::FSat0_1, "FSat(0 - 1)", "FF" },
110 	{ IROp::FSatMinus1_1, "FSat(-1 - 1)", "FF" },
111 	{ IROp::FMovFromGPR, "FMovFromGPR", "FG" },
112 	{ IROp::FMovToGPR, "FMovToGPR", "GF" },
113 	{ IROp::ZeroFpCond, "ZeroFpCond", "" },
114 	{ IROp::FpCondToReg, "FpCondToReg", "G" },
115 	{ IROp::VfpuCtrlToReg, "VfpuCtrlToReg", "GI" },
116 	{ IROp::SetCtrlVFPU, "SetCtrlVFPU", "TC" },
117 	{ IROp::SetCtrlVFPUReg, "SetCtrlVFPUReg", "TG" },
118 	{ IROp::SetCtrlVFPUFReg, "SetCtrlVFPUFReg", "TF" },
119 	{ IROp::FCmovVfpuCC, "FCmovVfpuCC", "FFI" },
120 	{ IROp::FCmpVfpuBit, "FCmpVfpuBit", "IFF" },
121 	{ IROp::FCmpVfpuAggregate, "FCmpVfpuAggregate", "I" },
122 	{ IROp::Vec4Init, "Vec4Init", "Vv" },
123 	{ IROp::Vec4Shuffle, "Vec4Shuffle", "VVs" },
124 	{ IROp::Vec4Mov, "Vec4Mov", "VV" },
125 	{ IROp::Vec4Add, "Vec4Add", "VVV" },
126 	{ IROp::Vec4Sub, "Vec4Sub", "VVV" },
127 	{ IROp::Vec4Div, "Vec4Div", "VVV" },
128 	{ IROp::Vec4Mul, "Vec4Mul", "VVV" },
129 	{ IROp::Vec4Scale, "Vec4Scale", "VVF" },
130 	{ IROp::Vec4Dot, "Vec4Dot", "FVV" },
131 	{ IROp::Vec4Neg, "Vec4Neg", "VV" },
132 	{ IROp::Vec4Abs, "Vec4Abs", "VV" },
133 
134 		// Pack/Unpack
135 	{ IROp::Vec2Unpack16To31, "Vec2Unpack16To31", "2F" },  // Note that the result is shifted down by 1, hence 31
136 	{ IROp::Vec2Unpack16To32, "Vec2Unpack16To32", "2F" },
137 	{ IROp::Vec4Unpack8To32, "Vec4Unpack8To32", "VF" },
138 	{ IROp::Vec4DuplicateUpperBitsAndShift1, "Vec4DuplicateUpperBitsAndShift1", "VV" },
139 
140 	{ IROp::Vec4ClampToZero, "Vec4ClampToZero", "VV" },
141 	{ IROp::Vec2ClampToZero, "Vec2ClampToZero", "22" },
142 	{ IROp::Vec4Pack32To8, "Vec4Pack32To8", "FV" },
143 	{ IROp::Vec4Pack31To8, "Vec4Pack31To8", "FV" },
144 	{ IROp::Vec2Pack32To16, "Vec2Pack32To16", "2V" },
145 	{ IROp::Vec2Pack31To16, "Vec2Pack31To16", "2V" },
146 
147 	{ IROp::Interpret, "Interpret", "_C" },
148 	{ IROp::Downcount, "Downcount", "_C" },
149 	{ IROp::ExitToPC, "ExitToPC", "", IRFLAG_EXIT },
150 	{ IROp::ExitToConst, "Exit", "C", IRFLAG_EXIT },
151 	{ IROp::ExitToConstIfEq, "ExitIfEq", "CGG", IRFLAG_EXIT },
152 	{ IROp::ExitToConstIfNeq, "ExitIfNeq", "CGG", IRFLAG_EXIT },
153 	{ IROp::ExitToConstIfGtZ, "ExitIfGtZ", "CG", IRFLAG_EXIT },
154 	{ IROp::ExitToConstIfGeZ, "ExitIfGeZ", "CG", IRFLAG_EXIT },
155 	{ IROp::ExitToConstIfLeZ, "ExitIfLeZ", "CG", IRFLAG_EXIT },
156 	{ IROp::ExitToConstIfLtZ, "ExitIfLtZ", "CG", IRFLAG_EXIT },
157 	{ IROp::ExitToReg, "ExitToReg", "_G", IRFLAG_EXIT },
158 	{ IROp::Syscall, "Syscall", "_C", IRFLAG_EXIT },
159 	{ IROp::Break, "Break", "", IRFLAG_EXIT },
160 	{ IROp::SetPC, "SetPC", "_G" },
161 	{ IROp::SetPCConst, "SetPC", "_C" },
162 	{ IROp::CallReplacement, "CallRepl", "_C" },
163 	{ IROp::Breakpoint, "Breakpoint", "", IRFLAG_EXIT },
164 	{ IROp::MemoryCheck, "MemoryCheck", "_GC", IRFLAG_EXIT },
165 
166 	{ IROp::RestoreRoundingMode, "RestoreRoundingMode", "" },
167 	{ IROp::ApplyRoundingMode, "ApplyRoundingMode", "" },
168 	{ IROp::UpdateRoundingMode, "UpdateRoundingMode", "" },
169 };
170 
171 const IRMeta *metaIndex[256];
172 
InitIR()173 void InitIR() {
174 	for (size_t i = 0; i < ARRAY_SIZE(irMeta); i++) {
175 		metaIndex[(int)irMeta[i].op] = &irMeta[i];
176 	}
177 }
178 
Write(IROp op,u8 dst,u8 src1,u8 src2)179 void IRWriter::Write(IROp op, u8 dst, u8 src1, u8 src2) {
180 	IRInst inst;
181 	inst.op = op;
182 	inst.dest = dst;
183 	inst.src1 = src1;
184 	inst.src2 = src2;
185 	inst.constant = nextConst_;
186 	insts_.push_back(inst);
187 
188 	nextConst_ = 0;
189 }
190 
WriteSetConstant(u8 dst,u32 value)191 void IRWriter::WriteSetConstant(u8 dst, u32 value) {
192 	Write(IROp::SetConst, dst, AddConstant(value));
193 }
194 
AddConstant(u32 value)195 int IRWriter::AddConstant(u32 value) {
196 	nextConst_ = value;
197 	return 255;
198 }
199 
AddConstantFloat(float value)200 int IRWriter::AddConstantFloat(float value) {
201 	u32 val;
202 	memcpy(&val, &value, 4);
203 	return AddConstant(val);
204 }
205 
GetGPRName(int r)206 const char *GetGPRName(int r) {
207 	if (r < 32) {
208 		return currentDebugMIPS->GetRegName(0, r);
209 	}
210 	switch (r) {
211 	case IRTEMP_0: return "irtemp0";
212 	case IRTEMP_1: return "irtemp1";
213 	case IRTEMP_2: return "irtemp2";
214 	case IRTEMP_3: return "irtemp3";
215 	case IRTEMP_LHS: return "irtemp_lhs";
216 	case IRTEMP_RHS: return "irtemp_rhs";
217 	case IRTEMP_LR_ADDR: return "irtemp_addr";
218 	case IRTEMP_LR_VALUE: return "irtemp_value";
219 	case IRTEMP_LR_MASK: return "irtemp_mask";
220 	case IRTEMP_LR_SHIFT: return "irtemp_shift";
221 	default: return "(unk)";
222 	}
223 }
224 
DisassembleParam(char * buf,int bufSize,u8 param,char type,u32 constant)225 void DisassembleParam(char *buf, int bufSize, u8 param, char type, u32 constant) {
226 	static const char *vfpuCtrlNames[VFPU_CTRL_MAX] = {
227 		"SPFX",
228 		"TPFX",
229 		"DPFX",
230 		"CC",
231 		"INF4",
232 		"RSV5",
233 		"RSV6",
234 		"REV",
235 		"RCX0",
236 		"RCX1",
237 		"RCX2",
238 		"RCX3",
239 		"RCX4",
240 		"RCX5",
241 		"RCX6",
242 		"RCX7",
243 	};
244 	static const char *initVec4Names[8] = {
245 		"[0 0 0 0]",
246 		"[1 1 1 1]",
247 		"[-1 -1 -1 -1]",
248 		"[1 0 0 0]",
249 		"[0 1 0 0]",
250 		"[0 0 1 0]",
251 		"[0 0 0 1]",
252 	};
253 	static const char *xyzw = "xyzw";
254 
255 	switch (type) {
256 	case 'G':
257 		snprintf(buf, bufSize, "%s", GetGPRName(param));
258 		break;
259 	case 'F':
260 		if (param >= 32) {
261 			snprintf(buf, bufSize, "v%d", param - 32);
262 		} else {
263 			snprintf(buf, bufSize, "f%d", param);
264 		}
265 		break;
266 	case 'V':
267 		if (param >= 32) {
268 			snprintf(buf, bufSize, "v%d..v%d", param - 32, param - 32 + 3);
269 		} else {
270 			snprintf(buf, bufSize, "f%d..f%d", param, param + 3);
271 		}
272 		break;
273 	case '2':
274 		if (param >= 32) {
275 			snprintf(buf, bufSize, "v%d,v%d", param - 32, param - 32 + 1);
276 		} else {
277 			snprintf(buf, bufSize, "f%d,f%d", param, param + 1);
278 		}
279 		break;
280 	case 'C':
281 		snprintf(buf, bufSize, "%08x", constant);
282 		break;
283 	case 'I':
284 		snprintf(buf, bufSize, "%02x", param);
285 		break;
286 	case 'm':
287 		snprintf(buf, bufSize, "%d", param);
288 		break;
289 	case 'T':
290 		snprintf(buf, bufSize, "%s", vfpuCtrlNames[param]);
291 		break;
292 	case 'v':
293 		snprintf(buf, bufSize, "%s", initVec4Names[param]);
294 		break;
295 	case 's':
296 		snprintf(buf, bufSize, "%c%c%c%c", xyzw[param & 3], xyzw[(param >> 2) & 3], xyzw[(param >> 4) & 3], xyzw[(param >> 6) & 3]);
297 		break;
298 	case '_':
299 	case '\0':
300 		buf[0] = 0;
301 		break;
302 	default:
303 		snprintf(buf, bufSize, "?");
304 		break;
305 	}
306 }
307 
GetIRMeta(IROp op)308 const IRMeta *GetIRMeta(IROp op) {
309 	return metaIndex[(int)op];
310 }
311 
DisassembleIR(char * buf,size_t bufsize,IRInst inst)312 void DisassembleIR(char *buf, size_t bufsize, IRInst inst) {
313 	const IRMeta *meta = GetIRMeta(inst.op);
314 	if (!meta) {
315 		snprintf(buf, bufsize, "Unknown %d", (int)inst.op);
316 		return;
317 	}
318 	char bufDst[16];
319 	char bufSrc1[16];
320 	char bufSrc2[16];
321 	DisassembleParam(bufDst, sizeof(bufDst) - 2, inst.dest, meta->types[0], inst.constant);
322 	DisassembleParam(bufSrc1, sizeof(bufSrc1) - 2, inst.src1, meta->types[1], inst.constant);
323 	DisassembleParam(bufSrc2, sizeof(bufSrc2), inst.src2, meta->types[2], inst.constant);
324 	if (meta->types[1] && meta->types[0] != '_') {
325 		strcat(bufDst, ", ");
326 	}
327 	if (meta->types[2] && meta->types[1] != '_') {
328 		strcat(bufSrc1, ", ");
329 	}
330 	snprintf(buf, bufsize, "%s %s%s%s", meta->name, bufDst, bufSrc1, bufSrc2);
331 }
332