improve ARM feature detection
[pcsx_rearmed.git] / libpcsxcore / ppc / reguse.c
CommitLineData
ef79bbde
P
1
2#include "../psxcommon.h"
3#include "reguse.h"
4
5#include "../r3000a.h"
6
7//#define SAME_CYCLE_MODE
8
9static const int useBSC[64] = {
10 /*recSPECIAL*/ REGUSE_SUB | REGUSE_SPECIAL,
11 /*recREGIMM*/ REGUSE_SUB | REGUSE_REGIMM,
12 /*recJ*/ REGUSE_JUMP,
13 /*recJAL*/ REGUSE_JUMP | REGUSE_R31_W,
14 /*recBEQ*/ REGUSE_BRANCH | REGUSE_RS_R | REGUSE_RT_R,
15 /*recBNE*/ REGUSE_BRANCH | REGUSE_RS_R | REGUSE_RT_R,
16 /*recBLEZ*/ REGUSE_BRANCH | REGUSE_RS_R,
17 /*recBGTZ*/ REGUSE_BRANCH | REGUSE_RS_R,
18 /*recADDI*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_W,
19 /*recADDIU*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_W,
20 /*recSLTI*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_W,
21 /*recSLTIU*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_W,
22 /*recANDI*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_RT_W,
23 /*recORI*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_RT_W,
24 /*recXORI*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_RT_W,
25 /*recLUI*/ REGUSE_ACC | REGUSE_RT_W,
26 /*recCOP0*/ REGUSE_SUB | REGUSE_COP0,
27 REGUSE_NONE,
28 /*recCOP2*/ REGUSE_SUB | REGUSE_COP2,
29 REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE,
30 REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE,
31 REGUSE_NONE, REGUSE_NONE, REGUSE_NONE,
32 /*recLB*/ REGUSE_MEM_R | REGUSE_RS_R | REGUSE_RT_W,
33 /*recLH*/ REGUSE_MEM_R | REGUSE_RS_R | REGUSE_RT_W,
34 /*recLWL*/ REGUSE_MEM_R | REGUSE_RS_R | REGUSE_RT,
35 /*recLW*/ REGUSE_MEM_R | REGUSE_RS_R | REGUSE_RT_W,
36 /*recLBU*/ REGUSE_MEM_R | REGUSE_RS_R | REGUSE_RT_W,
37 /*recLHU*/ REGUSE_MEM_R | REGUSE_RS_R | REGUSE_RT_W,
38 /*recLWR*/ REGUSE_MEM_R | REGUSE_RS_R | REGUSE_RT,
39 REGUSE_NONE,
40 /*recSB*/ REGUSE_MEM_W | REGUSE_RS_R | REGUSE_RT_R,
41 /*recSH*/ REGUSE_MEM_W | REGUSE_RS_R | REGUSE_RT_R,
42 /*recSWL*/ REGUSE_MEM | REGUSE_RS_R | REGUSE_RT_R,
43 /*recSW*/ REGUSE_MEM_W | REGUSE_RS_R | REGUSE_RT_R,
44 REGUSE_NONE, REGUSE_NONE,
45 /*recSWR*/ REGUSE_MEM | REGUSE_RS_R | REGUSE_RT_R,
46 REGUSE_NONE, REGUSE_NONE, REGUSE_NONE,
47 /*recLWC2*/ REGUSE_MEM_R | REGUSE_RS_R | REGUSE_COP2_RT_W,
48 REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE,
49 REGUSE_NONE, REGUSE_NONE,
50 /*recSWC2*/ REGUSE_MEM_W | REGUSE_RS_R | REGUSE_COP2_RT_R,
51 /*recHLE*/ REGUSE_UNKNOWN, // TODO: can this be done in a better way
52 REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE
53};
54
55static const int useSPC[64] = {
56 /*recSLL*/ REGUSE_ACC | REGUSE_RT_R | REGUSE_RD_W,
57 REGUSE_NONE,
58 /*recSRL*/ REGUSE_ACC | REGUSE_RT_R | REGUSE_RD_W,
59 /*recSRA*/ REGUSE_ACC | REGUSE_RT_R | REGUSE_RD_W,
60 /*recSLLV*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W,
61 REGUSE_NONE,
62 /*recSRLV*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W,
63 /*recSRAV*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W,
64 /*recJR*/ REGUSE_JUMPR | REGUSE_RS_R,
65 /*recJALR*/ REGUSE_JUMPR | REGUSE_RS_R | REGUSE_RD_W,
66 REGUSE_NONE, REGUSE_NONE,
67 /*rSYSCALL*/ REGUSE_SYS | REGUSE_PC | REGUSE_COP0_STATUS | REGUSE_EXCEPTION,
68 /*recBREAK*/ REGUSE_NONE,
69 REGUSE_NONE, REGUSE_NONE,
70 /*recMFHI*/ REGUSE_LOGIC | REGUSE_RD_W | REGUSE_HI_R,
71 /*recMTHI*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_HI_W,
72 /*recMFLO*/ REGUSE_LOGIC | REGUSE_RD_W | REGUSE_LO_R,
73 /*recMTLO*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_LO_W,
74 REGUSE_NONE, REGUSE_NONE , REGUSE_NONE, REGUSE_NONE,
75 /*recMULT*/ REGUSE_MULT | REGUSE_RS_R | REGUSE_RT_R | REGUSE_LO_W | REGUSE_HI_W,
76 /*recMULTU*/ REGUSE_MULT | REGUSE_RS_R | REGUSE_RT_R | REGUSE_LO_W | REGUSE_HI_W,
77 /*recDIV*/ REGUSE_MULT | REGUSE_RS_R | REGUSE_RT_R | REGUSE_LO_W | REGUSE_HI_W,
78 /*recDIVU*/ REGUSE_MULT | REGUSE_RS_R | REGUSE_RT_R | REGUSE_LO_W | REGUSE_HI_W,
79 REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE,
80 /*recADD*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W,
81 /*recADDU*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W,
82 /*recSUB*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W,
83 /*recSUBU*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W,
84 /*recAND*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W,
85 /*recOR*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W,
86 /*recXOR*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W,
87 /*recNOR*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W,
88 REGUSE_NONE, REGUSE_NONE,
89 /*recSLT*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W,
90 /*recSLTU*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W,
91 REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE,
92 REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE,
93 REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE,
94 REGUSE_NONE, REGUSE_NONE
95};
96
97static const int useREGIMM[32] = {
98 /*recBLTZ*/ REGUSE_BRANCH | REGUSE_RS_R,
99 /*recBGEZ*/ REGUSE_BRANCH | REGUSE_RS_R,
100 REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE,
101 REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE,
102 REGUSE_NONE, REGUSE_NONE,
103 /*recBLTZAL*/REGUSE_BRANCH | REGUSE_RS_R | REGUSE_R31_W,
104 /*recBGEZAL*/REGUSE_BRANCH | REGUSE_RS_R | REGUSE_R31_W,
105 REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE,
106 REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE,
107 REGUSE_NONE, REGUSE_NONE
108};
109
110static const int useCP0[32] = {
111 /*recMFC0*/ REGUSE_LOGIC | REGUSE_RT_W | REGUSE_COP0_RD_R,
112 REGUSE_NONE,
113 /*recCFC0*/ REGUSE_LOGIC | REGUSE_RT_W | REGUSE_COP0_RD_R,
114 REGUSE_NONE,
115 /*recMTC0*/ REGUSE_LOGIC | REGUSE_RT_R | REGUSE_COP0_RD_W,
116 REGUSE_NONE,
117 /*recCTC0*/ REGUSE_LOGIC | REGUSE_RT_R | REGUSE_COP0_RD_W,
118 REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE,
119 REGUSE_NONE, REGUSE_NONE, REGUSE_NONE,
120 /*recRFE*/ REGUSE_LOGIC | REGUSE_COP0_STATUS,
121 REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE,
122 REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE,
123 REGUSE_NONE, REGUSE_NONE, REGUSE_NONE
124};
125
126// TODO: make more explicit
127static const int useCP2[64] = {
128 /*recBASIC*/ REGUSE_SUB | REGUSE_BASIC,
129 /*recRTPS*/ REGUSE_GTE,
130 REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE,
131 /*recNCLIP*/ REGUSE_GTE,
132 REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE,
133 /*recOP*/ REGUSE_GTE,
134 REGUSE_NONE, REGUSE_NONE, REGUSE_NONE,
135 /*recDPCS*/ REGUSE_GTE,
136 /*recINTPL*/ REGUSE_GTE,
137 /*recMVMVA*/ REGUSE_GTE,
138 /*recNCDS*/ REGUSE_GTE,
139 /*recCDP*/ REGUSE_GTE,
140 REGUSE_NONE,
141 /*recNCDT*/ REGUSE_GTE,
142 REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE,
143 /*recNCCS*/ REGUSE_GTE,
144 /*recCC*/ REGUSE_GTE,
145 REGUSE_NONE,
146 /*recNCS*/ REGUSE_GTE,
147 REGUSE_NONE,
148 /*recNCT*/ REGUSE_GTE,
149 REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE,
150 REGUSE_NONE,
151 /*recSQR*/ REGUSE_GTE,
152 /*recDCPL*/ REGUSE_GTE,
153 /*recDPCT*/ REGUSE_GTE,
154 REGUSE_NONE, REGUSE_NONE,
155 /*recAVSZ3*/ REGUSE_GTE,
156 /*recAVSZ4*/ REGUSE_GTE,
157 REGUSE_NONE,
158 /*recRTPT*/ REGUSE_GTE,
159 REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE,
160 REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE,
161 /*recGPF*/ REGUSE_GTE,
162 /*recGPL*/ REGUSE_GTE,
163 /*recNCCT*/ REGUSE_GTE
164};
165
166static const int useCP2BSC[32] = {
167 /*recMFC2*/ REGUSE_LOGIC | REGUSE_RT_W | REGUSE_COP2_RD_R,
168 REGUSE_NONE,
169 /*recCFC2*/ REGUSE_LOGIC | REGUSE_RT_W | REGUSE_COP2_RD_R,
170 REGUSE_NONE,
171 /*recMTC2*/ REGUSE_LOGIC | REGUSE_RT_R | REGUSE_COP2_RD_W,
172 REGUSE_NONE,
173 /*recCTC2*/ REGUSE_LOGIC | REGUSE_RT_R | REGUSE_COP2_RD_W,
174 REGUSE_NONE,
175 REGUSE_NONE,
176 REGUSE_NONE,
177 REGUSE_NONE,
178 REGUSE_NONE,
179 REGUSE_NONE,
180 REGUSE_NONE,
181 REGUSE_NONE,
182 REGUSE_NONE,
183 REGUSE_NONE,
184 REGUSE_NONE,
185 REGUSE_NONE,
186 REGUSE_NONE,
187 REGUSE_NONE,
188 REGUSE_NONE,
189 REGUSE_NONE,
190 REGUSE_NONE,
191 REGUSE_NONE,
192 REGUSE_NONE,
193 REGUSE_NONE,
194 REGUSE_NONE,
195 REGUSE_NONE,
196 REGUSE_NONE,
197 REGUSE_NONE,
198 REGUSE_NONE
199};
200
201static int getRegUse(u32 code) __attribute__ ((__pure__));
202static int getRegUse(u32 code)
203{
204 int use = useBSC[code>>26];
205
206 switch (use & REGUSE_SUBMASK) {
207 case REGUSE_NONE:
208 break;
209 case REGUSE_SPECIAL:
210 use = useSPC[_fFunct_(code)];
211 break;
212 case REGUSE_REGIMM:
213 use = useREGIMM[_fRt_(code)];
214 break;
215 case REGUSE_COP0:
216 use = useCP0[_fRs_(code)];
217 break;
218 case REGUSE_COP2:
219 use = useCP2[_fFunct_(code)];
220 if ((use & REGUSE_SUBMASK) == REGUSE_BASIC)
221 use = useCP2BSC[_fRs_(code)];
222 break;
223 default:
224 use = REGUSE_UNKNOWN;
225 break;
226 }
227
228 if ((use & REGUSE_COP0_RD_W)) {
229 if (_fRd_(code) == 12 || _fRd_(code) == 13) {
230 use = REGUSE_UNKNOWN;
231 }
232 }
233
234 return use;
235}
236
237/* returns how psxreg is used in the code instruction */
238int useOfPsxReg(u32 code, int use, int psxreg)
239{
240 int retval = REGUSE_NONE;
241
242 // get use if it wasn't supplied
243 if (-1 == use) use = getRegUse(code);
244
245 // if we don't know what the usage is, assume it's read from
246 if (REGUSE_UNKNOWN == use) return REGUSE_READ;
247
248 if (psxreg < 32) {
249 // check for 3 standard types
250 if ((use & REGUSE_RT) && _fRt_(code) == (u32)psxreg) {
251 retval |= ((use & REGUSE_RT_R) ? REGUSE_READ:0) | ((use & REGUSE_RT_W) ? REGUSE_WRITE:0);
252 }
253 if ((use & REGUSE_RS) && _fRs_(code) == (u32)psxreg) {
254 retval |= ((use & REGUSE_RS_R) ? REGUSE_READ:0) | ((use & REGUSE_RS_W) ? REGUSE_WRITE:0);
255 }
256 if ((use & REGUSE_RD) && _fRd_(code) == (u32)psxreg) {
257 retval |= ((use & REGUSE_RD_R) ? REGUSE_READ:0) | ((use & REGUSE_RD_W) ? REGUSE_WRITE:0);
258 }
259 // some instructions explicitly writes to r31
260 if ((use & REGUSE_R31_W) && 31 == psxreg) {
261 retval |= REGUSE_WRITE;
262 }
263 } else if (psxreg == 32) { // Special register LO
264 retval |= ((use & REGUSE_LO_R) ? REGUSE_READ:0) | ((use & REGUSE_LO_W) ? REGUSE_WRITE:0);
265 } else if (psxreg == 33) { // Special register HI
266 retval |= ((use & REGUSE_HI_R) ? REGUSE_READ:0) | ((use & REGUSE_HI_W) ? REGUSE_WRITE:0);
267 }
268
269 return retval;
270}
271
272//#define NOREGUSE_FOLLOW
273
274static int _nextPsxRegUse(u32 pc, int psxreg, int numInstr) __attribute__ ((__pure__, __unused__));
275static int _nextPsxRegUse(u32 pc, int psxreg, int numInstr)
276{
277 u32 *ptr, code, bPC = 0;
278 int i, use, reguse = 0;
279
280 for (i=0; i<numInstr; ) {
281 // load current instruction
282 ptr = PSXM(pc);
283 if (ptr==NULL) {
284 // going nowhere... might as well assume a write, since we will hopefully never reach here
285 reguse = REGUSE_WRITE;
286 break;
287 }
288 code = SWAP32(*ptr);
289 // get usage patterns for instruction
290 use = getRegUse(code);
291 // find the use of psxreg in the instruction
292 reguse = useOfPsxReg(code, use, psxreg);
293
294 // return if we have found a use
295 if (reguse != REGUSE_NONE)
296 break;
297
298 // goto next instruction
299 pc += 4;
300 i++;
301
302 // check for code branches/jumps
303 if (i != numInstr) {
304 if ((use & REGUSE_TYPEM) == REGUSE_BRANCH) {
305#ifndef NOREGUSE_FOLLOW
306 // check delay slot
307 reguse = _nextPsxRegUse(pc, psxreg, 1);
308 if (reguse != REGUSE_NONE) break;
309
310 bPC = _fImm_(code) * 4 + pc;
311 reguse = _nextPsxRegUse(pc+4, psxreg, (numInstr-i-1)/2);
312 if (reguse != REGUSE_NONE) {
313 int reguse2 = _nextPsxRegUse(bPC, psxreg, (numInstr-i-1)/2);
314 if (reguse2 != REGUSE_NONE)
315 reguse |= reguse2;
316 else
317 reguse = REGUSE_NONE;
318 }
319#endif
320 break;
321 } else if ((use & REGUSE_TYPEM) == REGUSE_JUMP) {
322#ifndef NOREGUSE_FOLLOW
323 // check delay slot
324 reguse = _nextPsxRegUse(pc, psxreg, 1);
325 if (reguse != REGUSE_NONE) break;
326
327 bPC = _fTarget_(code) * 4 + (pc & 0xf0000000);
328 reguse = _nextPsxRegUse(bPC, psxreg, numInstr-i-1);
329#endif
330 break;
331 } else if ((use & REGUSE_TYPEM) == REGUSE_JUMPR) {
332#ifndef NOREGUSE_FOLLOW
333 // jump to unknown location - bail after checking delay slot
334 reguse = _nextPsxRegUse(pc, psxreg, 1);
335#endif
336 break;
337 } else if ((use & REGUSE_TYPEM) == REGUSE_SYS) {
338 break;
339 }
340 }
341 }
342
343 return reguse;
344}
345
346
347int nextPsxRegUse(u32 pc, int psxreg)
348{
349#if 1
350 if (psxreg == 0)
351 return REGUSE_WRITE; // pretend we are writing to it to fool compiler
352
353#ifdef SAME_CYCLE_MODE
354 return REGUSE_READ;
355#else
356 return _nextPsxRegUse(pc, psxreg, 80);
357#endif
358#else
359 u32 code, bPC = 0;
360 int use, reguse = 0, reguse1 = 0, b = 0, i, index = 0;
361
362retry:
363 for (i=index; i<80; i++) {
364 code = PSXMu32(pc);
365 use = getRegUse(code);
366 reguse = useOfPsxReg(code, use, psxreg);
367
368 if (reguse != REGUSE_NONE) break;
369
370 pc += 4;
371 if ((use & REGUSE_TYPEM) == REGUSE_BRANCH) {
372 if (b == 0) {
373 bPC = _fImm_(code) * 4 + pc;
374 index = i+1;
375 }
376 b += 1; // TODO: follow branches
377 continue;
378 } else if ((use & REGUSE_TYPEM) == REGUSE_JUMP) {
379 if (b == 0) {
380 bPC = _fTarget_(code) * 4 + (pc & 0xf0000000);
381 }
382 b = 2;
383 continue;
384 } else if ((use & REGUSE_TYPEM) == REGUSE_JUMPR ||
385 (use & REGUSE_TYPEM) == REGUSE_SYS) {
386 b = 2;
387 continue;
388 }
389
390 if (b == 2 && bPC && index == 0) {
391 pc = bPC; bPC = 0;
392 b = 1;
393 }
394 if (b >= 2) break; // only follow 1 branch
395 }
396 if (reguse == REGUSE_NONE) return reguse;
397
398 if (bPC) {
399 reguse1 = reguse;
400 pc = bPC; bPC = 0;
401 b = 1;
402 goto retry;
403 }
404
405 return reguse1 | reguse;
406#endif
407}
408
409int isPsxRegUsed(u32 pc, int psxreg)
410{
411 int use = nextPsxRegUse(pc, psxreg);
412
413 if (use == REGUSE_NONE)
414 return 2; // unknown use - assume it is used
415 else if (use & REGUSE_READ)
416 return 1; // the next use is a read
417 else
418 return 0; // the next use is a write, i.e. current value is not important
419}