cdrom: remove cdrWrite3 reschedule
[pcsx_rearmed.git] / libpcsxcore / ppc / reguse.c
1
2 #include "../psxcommon.h"
3 #include "reguse.h"
4
5 #include "../r3000a.h"
6
7 //#define SAME_CYCLE_MODE
8
9 static 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
55 static 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
97 static 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
110 static 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
127 static 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
166 static 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
201 static int getRegUse(u32 code) __attribute__ ((__pure__));
202 static 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 */
238 int 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
274 static int _nextPsxRegUse(u32 pc, int psxreg, int numInstr) __attribute__ ((__pure__, __unused__));
275 static 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
347 int 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
362 retry:
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
409 int 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 }