Commit | Line | Data |
---|---|---|
ef79bbde P |
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 | } |