Commit | Line | Data |
---|---|---|
ef79bbde P |
1 | /*************************************************************************** |
2 | * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * | |
3 | * * | |
4 | * This program is free software; you can redistribute it and/or modify * | |
5 | * it under the terms of the GNU General Public License as published by * | |
6 | * the Free Software Foundation; either version 2 of the License, or * | |
7 | * (at your option) any later version. * | |
8 | * * | |
9 | * This program is distributed in the hope that it will be useful, * | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | |
12 | * GNU General Public License for more details. * | |
13 | * * | |
14 | * You should have received a copy of the GNU General Public License * | |
15 | * along with this program; if not, write to the * | |
16 | * Free Software Foundation, Inc., * | |
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA. * | |
18 | ***************************************************************************/ | |
19 | ||
20 | /* | |
21 | * PSX assembly interpreter. | |
22 | */ | |
23 | ||
24 | #include "psxcommon.h" | |
25 | #include "r3000a.h" | |
26 | #include "gte.h" | |
27 | #include "psxhle.h" | |
3968e69e | 28 | #include "psxinterpreter.h" |
4cc373dd | 29 | #include <stddef.h> |
32631e6a | 30 | #include <assert.h> |
7d7672a5 | 31 | //#include "debug.h" |
32 | #define ProcessDebug() | |
ef79bbde P |
33 | |
34 | static int branch = 0; | |
35 | static int branch2 = 0; | |
36 | static u32 branchPC; | |
37 | ||
38 | // These macros are used to assemble the repassembler functions | |
39 | ||
40 | #ifdef PSXCPU_LOG | |
41 | #define debugI() PSXCPU_LOG("%s\n", disR3000AF(psxRegs.code, psxRegs.pc)); | |
42 | #else | |
43 | #define debugI() | |
44 | #endif | |
45 | ||
4cc373dd | 46 | #ifdef __i386__ |
47 | #define INT_ATTR __attribute__((regparm(2))) | |
48 | #else | |
49 | #define INT_ATTR | |
50 | #endif | |
51 | #ifndef INVALID_PTR | |
52 | #define INVALID_PTR NULL | |
53 | #endif | |
54 | ||
ef79bbde | 55 | // Subsets |
4cc373dd | 56 | static void (INT_ATTR *psxBSC[64])(psxRegisters *regs_, u32 code); |
57 | static void (INT_ATTR *psxSPC[64])(psxRegisters *regs_, u32 code); | |
58 | ||
59 | static u32 INT_ATTR fetchNoCache(u8 **memRLUT, u32 pc) | |
61ad2a61 | 60 | { |
4cc373dd | 61 | u8 *base = memRLUT[pc >> 16]; |
62 | if (base == INVALID_PTR) | |
63 | return 0; | |
64 | u32 *code = (u32 *)(base + (pc & 0xfffc)); | |
65 | return SWAP32(*code); | |
61ad2a61 | 66 | } |
67 | ||
943a507a | 68 | /* |
69 | Formula One 2001 : | |
70 | Use old CPU cache code when the RAM location is updated with new code (affects in-game racing) | |
71 | */ | |
9f84fc93 | 72 | static struct cache_entry { |
73 | u32 tag; | |
74 | u32 data[4]; | |
75 | } ICache[256]; | |
76 | ||
4cc373dd | 77 | static u32 INT_ATTR fetchICache(u8 **memRLUT, u32 pc) |
943a507a | 78 | { |
9f84fc93 | 79 | // cached? |
80 | if (pc < 0xa0000000) | |
943a507a | 81 | { |
9f84fc93 | 82 | // this is not how the hardware works but whatever |
83 | struct cache_entry *entry = &ICache[(pc & 0xff0) >> 4]; | |
84 | ||
85 | if (((entry->tag ^ pc) & 0xfffffff0) != 0 || pc < entry->tag) | |
943a507a | 86 | { |
4cc373dd | 87 | const u8 *base = memRLUT[pc >> 16]; |
88 | const u32 *code; | |
89 | if (base == INVALID_PTR) | |
9f84fc93 | 90 | return 0; |
4cc373dd | 91 | code = (u32 *)(base + (pc & 0xfff0)); |
9f84fc93 | 92 | |
93 | entry->tag = pc; | |
94 | // treat as 4 words, although other configurations are said to be possible | |
95 | switch (pc & 0x0c) | |
96 | { | |
97 | case 0x00: entry->data[0] = SWAP32(code[0]); | |
98 | case 0x04: entry->data[1] = SWAP32(code[1]); | |
99 | case 0x08: entry->data[2] = SWAP32(code[2]); | |
100 | case 0x0c: entry->data[3] = SWAP32(code[3]); | |
101 | } | |
943a507a | 102 | } |
9f84fc93 | 103 | return entry->data[(pc & 0x0f) >> 2]; |
943a507a | 104 | } |
105 | ||
4cc373dd | 106 | return fetchNoCache(memRLUT, pc); |
943a507a | 107 | } |
61ad2a61 | 108 | |
4cc373dd | 109 | static u32 (INT_ATTR *fetch)(u8 **memRLUT, u32 pc) = fetchNoCache; |
943a507a | 110 | |
d5aeda23 | 111 | // Make the timing events trigger faster as we are currently assuming everything |
112 | // takes one cycle, which is not the case on real hardware. | |
113 | // FIXME: count cache misses, memory latencies, stalls to get rid of this | |
114 | static inline void addCycle(void) | |
115 | { | |
116 | assert(psxRegs.subCycleStep >= 0x10000); | |
117 | psxRegs.subCycle += psxRegs.subCycleStep; | |
118 | psxRegs.cycle += psxRegs.subCycle >> 16; | |
119 | psxRegs.subCycle &= 0xffff; | |
120 | } | |
121 | ||
ef79bbde P |
122 | static void delayRead(int reg, u32 bpc) { |
123 | u32 rold, rnew; | |
124 | ||
125 | // SysPrintf("delayRead at %x!\n", psxRegs.pc); | |
126 | ||
127 | rold = psxRegs.GPR.r[reg]; | |
4cc373dd | 128 | psxBSC[psxRegs.code >> 26](&psxRegs, psxRegs.code); // branch delay load |
ef79bbde P |
129 | rnew = psxRegs.GPR.r[reg]; |
130 | ||
131 | psxRegs.pc = bpc; | |
132 | ||
abbc1ca1 | 133 | branch = 0; |
ef79bbde P |
134 | |
135 | psxRegs.GPR.r[reg] = rold; | |
136 | execI(); // first branch opcode | |
137 | psxRegs.GPR.r[reg] = rnew; | |
138 | ||
abbc1ca1 | 139 | psxBranchTest(); |
ef79bbde P |
140 | } |
141 | ||
142 | static void delayWrite(int reg, u32 bpc) { | |
143 | ||
144 | /* SysPrintf("delayWrite at %x!\n", psxRegs.pc); | |
145 | ||
146 | SysPrintf("%s\n", disR3000AF(psxRegs.code, psxRegs.pc-4)); | |
147 | SysPrintf("%s\n", disR3000AF(PSXMu32(bpc), bpc));*/ | |
148 | ||
149 | // no changes from normal behavior | |
150 | ||
4cc373dd | 151 | psxBSC[psxRegs.code >> 26](&psxRegs, psxRegs.code); |
ef79bbde P |
152 | |
153 | branch = 0; | |
154 | psxRegs.pc = bpc; | |
155 | ||
156 | psxBranchTest(); | |
157 | } | |
158 | ||
159 | static void delayReadWrite(int reg, u32 bpc) { | |
160 | ||
161 | // SysPrintf("delayReadWrite at %x!\n", psxRegs.pc); | |
162 | ||
163 | // the branch delay load is skipped | |
164 | ||
165 | branch = 0; | |
166 | psxRegs.pc = bpc; | |
167 | ||
168 | psxBranchTest(); | |
169 | } | |
170 | ||
4cc373dd | 171 | /**** R3000A Instruction Macros ****/ |
172 | #define _PC_ regs_->pc // The next PC to be executed | |
173 | ||
174 | #define _fOp_(code) ((code >> 26) ) // The opcode part of the instruction register | |
175 | #define _fFunct_(code) ((code ) & 0x3F) // The funct part of the instruction register | |
176 | #define _fRd_(code) ((code >> 11) & 0x1F) // The rd part of the instruction register | |
177 | #define _fRt_(code) ((code >> 16) & 0x1F) // The rt part of the instruction register | |
178 | #define _fRs_(code) ((code >> 21) & 0x1F) // The rs part of the instruction register | |
179 | #define _fSa_(code) ((code >> 6) & 0x1F) // The sa part of the instruction register | |
180 | #define _fIm_(code) ((u16)code) // The immediate part of the instruction register | |
181 | #define _fTarget_(code) (code & 0x03ffffff) // The target part of the instruction register | |
182 | ||
183 | #define _fImm_(code) ((s16)code) // sign-extended immediate | |
184 | #define _fImmU_(code) (code&0xffff) // zero-extended immediate | |
185 | ||
186 | #define _Op_ _fOp_(code) | |
187 | #define _Funct_ _fFunct_(code) | |
188 | #define _Rd_ _fRd_(code) | |
189 | #define _Rt_ _fRt_(code) | |
190 | #define _Rs_ _fRs_(code) | |
191 | #define _Sa_ _fSa_(code) | |
192 | #define _Im_ _fIm_(code) | |
193 | #define _Target_ _fTarget_(code) | |
194 | ||
195 | #define _Imm_ _fImm_(code) | |
196 | #define _ImmU_ _fImmU_(code) | |
197 | ||
198 | #define _rRs_ regs_->GPR.r[_Rs_] // Rs register | |
199 | #define _rRt_ regs_->GPR.r[_Rt_] // Rt register | |
200 | #define _rRd_ regs_->GPR.r[_Rd_] // Rd register | |
201 | #define _rSa_ regs_->GPR.r[_Sa_] // Sa register | |
202 | #define _rFs_ regs_->CP0.r[_Rd_] // Fs register | |
203 | ||
204 | #define _rHi_ regs_->GPR.n.hi // The HI register | |
205 | #define _rLo_ regs_->GPR.n.lo // The LO register | |
206 | ||
207 | #define _JumpTarget_ ((_Target_ * 4) + (_PC_ & 0xf0000000)) // Calculates the target during a jump instruction | |
208 | #define _BranchTarget_ ((s16)_Im_ * 4 + _PC_) // Calculates the target during a branch instruction | |
209 | ||
210 | #define _SetLink(x) regs_->GPR.r[x] = _PC_ + 4; // Sets the return address in the link register | |
211 | ||
212 | #define OP(name) \ | |
213 | static inline INT_ATTR void name(psxRegisters *regs_, u32 code) | |
214 | ||
ef79bbde P |
215 | // this defines shall be used with the tmp |
216 | // of the next func (instead of _Funct_...) | |
217 | #define _tFunct_ ((tmp ) & 0x3F) // The funct part of the instruction register | |
218 | #define _tRd_ ((tmp >> 11) & 0x1F) // The rd part of the instruction register | |
219 | #define _tRt_ ((tmp >> 16) & 0x1F) // The rt part of the instruction register | |
220 | #define _tRs_ ((tmp >> 21) & 0x1F) // The rs part of the instruction register | |
221 | #define _tSa_ ((tmp >> 6) & 0x1F) // The sa part of the instruction register | |
222 | ||
4cc373dd | 223 | #define _i32(x) (s32)(x) |
224 | #define _u32(x) (u32)(x) | |
225 | ||
226 | static int psxTestLoadDelay(int reg, u32 tmp) { | |
ef79bbde P |
227 | if (tmp == 0) return 0; // NOP |
228 | switch (tmp >> 26) { | |
229 | case 0x00: // SPECIAL | |
230 | switch (_tFunct_) { | |
231 | case 0x00: // SLL | |
232 | case 0x02: case 0x03: // SRL/SRA | |
233 | if (_tRd_ == reg && _tRt_ == reg) return 1; else | |
234 | if (_tRt_ == reg) return 2; else | |
235 | if (_tRd_ == reg) return 3; | |
236 | break; | |
237 | ||
238 | case 0x08: // JR | |
239 | if (_tRs_ == reg) return 2; | |
240 | break; | |
241 | case 0x09: // JALR | |
242 | if (_tRd_ == reg && _tRs_ == reg) return 1; else | |
243 | if (_tRs_ == reg) return 2; else | |
244 | if (_tRd_ == reg) return 3; | |
245 | break; | |
246 | ||
247 | // SYSCALL/BREAK just a break; | |
248 | ||
249 | case 0x20: case 0x21: case 0x22: case 0x23: | |
250 | case 0x24: case 0x25: case 0x26: case 0x27: | |
251 | case 0x2a: case 0x2b: // ADD/ADDU... | |
252 | case 0x04: case 0x06: case 0x07: // SLLV... | |
253 | if (_tRd_ == reg && (_tRt_ == reg || _tRs_ == reg)) return 1; else | |
254 | if (_tRt_ == reg || _tRs_ == reg) return 2; else | |
255 | if (_tRd_ == reg) return 3; | |
256 | break; | |
257 | ||
258 | case 0x10: case 0x12: // MFHI/MFLO | |
259 | if (_tRd_ == reg) return 3; | |
260 | break; | |
261 | case 0x11: case 0x13: // MTHI/MTLO | |
262 | if (_tRs_ == reg) return 2; | |
263 | break; | |
264 | ||
265 | case 0x18: case 0x19: | |
266 | case 0x1a: case 0x1b: // MULT/DIV... | |
267 | if (_tRt_ == reg || _tRs_ == reg) return 2; | |
268 | break; | |
269 | } | |
270 | break; | |
271 | ||
272 | case 0x01: // REGIMM | |
273 | switch (_tRt_) { | |
862bfc0d | 274 | case 0x00: case 0x01: |
275 | case 0x10: case 0x11: // BLTZ/BGEZ... | |
276 | // Xenogears - lbu v0 / beq v0 | |
277 | // - no load delay (fixes battle loading) | |
278 | break; | |
279 | ||
ef79bbde P |
280 | if (_tRs_ == reg) return 2; |
281 | break; | |
282 | } | |
283 | break; | |
284 | ||
285 | // J would be just a break; | |
286 | case 0x03: // JAL | |
287 | if (31 == reg) return 3; | |
288 | break; | |
289 | ||
290 | case 0x04: case 0x05: // BEQ/BNE | |
862bfc0d | 291 | // Xenogears - lbu v0 / beq v0 |
292 | // - no load delay (fixes battle loading) | |
293 | break; | |
294 | ||
ef79bbde P |
295 | if (_tRs_ == reg || _tRt_ == reg) return 2; |
296 | break; | |
297 | ||
298 | case 0x06: case 0x07: // BLEZ/BGTZ | |
862bfc0d | 299 | // Xenogears - lbu v0 / beq v0 |
300 | // - no load delay (fixes battle loading) | |
301 | break; | |
302 | ||
ef79bbde P |
303 | if (_tRs_ == reg) return 2; |
304 | break; | |
305 | ||
306 | case 0x08: case 0x09: case 0x0a: case 0x0b: | |
307 | case 0x0c: case 0x0d: case 0x0e: // ADDI/ADDIU... | |
308 | if (_tRt_ == reg && _tRs_ == reg) return 1; else | |
309 | if (_tRs_ == reg) return 2; else | |
310 | if (_tRt_ == reg) return 3; | |
311 | break; | |
312 | ||
313 | case 0x0f: // LUI | |
314 | if (_tRt_ == reg) return 3; | |
315 | break; | |
316 | ||
317 | case 0x10: // COP0 | |
318 | switch (_tFunct_) { | |
319 | case 0x00: // MFC0 | |
320 | if (_tRt_ == reg) return 3; | |
321 | break; | |
322 | case 0x02: // CFC0 | |
323 | if (_tRt_ == reg) return 3; | |
324 | break; | |
325 | case 0x04: // MTC0 | |
326 | if (_tRt_ == reg) return 2; | |
327 | break; | |
328 | case 0x06: // CTC0 | |
329 | if (_tRt_ == reg) return 2; | |
330 | break; | |
331 | // RFE just a break; | |
332 | } | |
333 | break; | |
334 | ||
335 | case 0x12: // COP2 | |
336 | switch (_tFunct_) { | |
337 | case 0x00: | |
338 | switch (_tRs_) { | |
339 | case 0x00: // MFC2 | |
340 | if (_tRt_ == reg) return 3; | |
341 | break; | |
342 | case 0x02: // CFC2 | |
343 | if (_tRt_ == reg) return 3; | |
344 | break; | |
345 | case 0x04: // MTC2 | |
346 | if (_tRt_ == reg) return 2; | |
347 | break; | |
348 | case 0x06: // CTC2 | |
349 | if (_tRt_ == reg) return 2; | |
350 | break; | |
351 | } | |
352 | break; | |
353 | // RTPS... break; | |
354 | } | |
355 | break; | |
356 | ||
357 | case 0x22: case 0x26: // LWL/LWR | |
358 | if (_tRt_ == reg) return 3; else | |
359 | if (_tRs_ == reg) return 2; | |
360 | break; | |
361 | ||
362 | case 0x20: case 0x21: case 0x23: | |
363 | case 0x24: case 0x25: // LB/LH/LW/LBU/LHU | |
364 | if (_tRt_ == reg && _tRs_ == reg) return 1; else | |
365 | if (_tRs_ == reg) return 2; else | |
366 | if (_tRt_ == reg) return 3; | |
367 | break; | |
368 | ||
369 | case 0x28: case 0x29: case 0x2a: | |
370 | case 0x2b: case 0x2e: // SB/SH/SWL/SW/SWR | |
371 | if (_tRt_ == reg || _tRs_ == reg) return 2; | |
372 | break; | |
373 | ||
374 | case 0x32: case 0x3a: // LWC2/SWC2 | |
375 | if (_tRs_ == reg) return 2; | |
376 | break; | |
377 | } | |
378 | ||
379 | return 0; | |
380 | } | |
381 | ||
4cc373dd | 382 | static void psxDelayTest(int reg, u32 bpc) { |
383 | u32 tmp = fetch(psxMemRLUT, bpc); | |
ef79bbde P |
384 | branch = 1; |
385 | ||
386 | switch (psxTestLoadDelay(reg, tmp)) { | |
387 | case 1: | |
388 | delayReadWrite(reg, bpc); return; | |
389 | case 2: | |
390 | delayRead(reg, bpc); return; | |
391 | case 3: | |
392 | delayWrite(reg, bpc); return; | |
393 | } | |
19fae7fc | 394 | // DS |
4cc373dd | 395 | psxBSC[psxRegs.code >> 26](&psxRegs, psxRegs.code); |
ef79bbde P |
396 | |
397 | branch = 0; | |
398 | psxRegs.pc = bpc; | |
399 | ||
400 | psxBranchTest(); | |
401 | } | |
402 | ||
4cc373dd | 403 | static u32 psxBranchNoDelay(psxRegisters *regs_) { |
404 | u32 temp, code; | |
990cb018 | 405 | |
4cc373dd | 406 | regs_->code = code = fetch(psxMemRLUT, regs_->pc); |
990cb018 | 407 | switch (_Op_) { |
408 | case 0x00: // SPECIAL | |
409 | switch (_Funct_) { | |
410 | case 0x08: // JR | |
411 | return _u32(_rRs_); | |
412 | case 0x09: // JALR | |
413 | temp = _u32(_rRs_); | |
414 | if (_Rd_) { _SetLink(_Rd_); } | |
415 | return temp; | |
416 | } | |
417 | break; | |
418 | case 0x01: // REGIMM | |
419 | switch (_Rt_) { | |
420 | case 0x00: // BLTZ | |
421 | if (_i32(_rRs_) < 0) | |
422 | return _BranchTarget_; | |
423 | break; | |
424 | case 0x01: // BGEZ | |
425 | if (_i32(_rRs_) >= 0) | |
426 | return _BranchTarget_; | |
427 | break; | |
428 | case 0x08: // BLTZAL | |
429 | if (_i32(_rRs_) < 0) { | |
430 | _SetLink(31); | |
431 | return _BranchTarget_; | |
432 | } | |
433 | break; | |
434 | case 0x09: // BGEZAL | |
435 | if (_i32(_rRs_) >= 0) { | |
436 | _SetLink(31); | |
437 | return _BranchTarget_; | |
438 | } | |
439 | break; | |
440 | } | |
441 | break; | |
442 | case 0x02: // J | |
443 | return _JumpTarget_; | |
444 | case 0x03: // JAL | |
445 | _SetLink(31); | |
446 | return _JumpTarget_; | |
447 | case 0x04: // BEQ | |
448 | if (_i32(_rRs_) == _i32(_rRt_)) | |
449 | return _BranchTarget_; | |
450 | break; | |
451 | case 0x05: // BNE | |
452 | if (_i32(_rRs_) != _i32(_rRt_)) | |
453 | return _BranchTarget_; | |
454 | break; | |
455 | case 0x06: // BLEZ | |
456 | if (_i32(_rRs_) <= 0) | |
457 | return _BranchTarget_; | |
458 | break; | |
459 | case 0x07: // BGTZ | |
460 | if (_i32(_rRs_) > 0) | |
461 | return _BranchTarget_; | |
462 | break; | |
463 | } | |
464 | ||
465 | return (u32)-1; | |
466 | } | |
467 | ||
468 | static int psxDelayBranchExec(u32 tar) { | |
469 | execI(); | |
470 | ||
471 | branch = 0; | |
472 | psxRegs.pc = tar; | |
d5aeda23 | 473 | addCycle(); |
990cb018 | 474 | psxBranchTest(); |
475 | return 1; | |
476 | } | |
477 | ||
478 | static int psxDelayBranchTest(u32 tar1) { | |
479 | u32 tar2, tmp1, tmp2; | |
480 | ||
4cc373dd | 481 | tar2 = psxBranchNoDelay(&psxRegs); |
990cb018 | 482 | if (tar2 == (u32)-1) |
483 | return 0; | |
484 | ||
485 | debugI(); | |
486 | ||
487 | /* | |
488 | * Branch in delay slot: | |
489 | * - execute 1 instruction at tar1 | |
490 | * - jump to tar2 (target of branch in delay slot; this branch | |
491 | * has no normal delay slot, instruction at tar1 was fetched instead) | |
492 | */ | |
493 | psxRegs.pc = tar1; | |
4cc373dd | 494 | tmp1 = psxBranchNoDelay(&psxRegs); |
990cb018 | 495 | if (tmp1 == (u32)-1) { |
496 | return psxDelayBranchExec(tar2); | |
497 | } | |
498 | debugI(); | |
d5aeda23 | 499 | addCycle(); |
990cb018 | 500 | |
501 | /* | |
502 | * Got a branch at tar1: | |
503 | * - execute 1 instruction at tar2 | |
504 | * - jump to target of that branch (tmp1) | |
505 | */ | |
506 | psxRegs.pc = tar2; | |
4cc373dd | 507 | tmp2 = psxBranchNoDelay(&psxRegs); |
990cb018 | 508 | if (tmp2 == (u32)-1) { |
509 | return psxDelayBranchExec(tmp1); | |
510 | } | |
511 | debugI(); | |
d5aeda23 | 512 | addCycle(); |
990cb018 | 513 | |
514 | /* | |
515 | * Got a branch at tar2: | |
516 | * - execute 1 instruction at tmp1 | |
517 | * - jump to target of that branch (tmp2) | |
518 | */ | |
519 | psxRegs.pc = tmp1; | |
520 | return psxDelayBranchExec(tmp2); | |
521 | } | |
522 | ||
4600ba03 | 523 | static void doBranch(u32 tar) { |
4cc373dd | 524 | u32 tmp, code; |
ef79bbde P |
525 | |
526 | branch2 = branch = 1; | |
527 | branchPC = tar; | |
528 | ||
990cb018 | 529 | // check for branch in delay slot |
530 | if (psxDelayBranchTest(tar)) | |
531 | return; | |
532 | ||
4cc373dd | 533 | psxRegs.code = code = fetch(psxMemRLUT, psxRegs.pc); |
ef79bbde P |
534 | |
535 | debugI(); | |
536 | ||
537 | psxRegs.pc += 4; | |
d5aeda23 | 538 | addCycle(); |
ef79bbde P |
539 | |
540 | // check for load delay | |
19fae7fc | 541 | tmp = code >> 26; |
ef79bbde P |
542 | switch (tmp) { |
543 | case 0x10: // COP0 | |
544 | switch (_Rs_) { | |
545 | case 0x00: // MFC0 | |
546 | case 0x02: // CFC0 | |
547 | psxDelayTest(_Rt_, branchPC); | |
548 | return; | |
549 | } | |
550 | break; | |
551 | case 0x12: // COP2 | |
552 | switch (_Funct_) { | |
553 | case 0x00: | |
554 | switch (_Rs_) { | |
555 | case 0x00: // MFC2 | |
556 | case 0x02: // CFC2 | |
557 | psxDelayTest(_Rt_, branchPC); | |
558 | return; | |
559 | } | |
560 | break; | |
561 | } | |
562 | break; | |
563 | case 0x32: // LWC2 | |
564 | psxDelayTest(_Rt_, branchPC); | |
565 | return; | |
566 | default: | |
567 | if (tmp >= 0x20 && tmp <= 0x26) { // LB/LH/LWL/LW/LBU/LHU/LWR | |
568 | psxDelayTest(_Rt_, branchPC); | |
569 | return; | |
570 | } | |
571 | break; | |
572 | } | |
573 | ||
19fae7fc | 574 | psxBSC[code >> 26](&psxRegs, code); |
ef79bbde P |
575 | |
576 | branch = 0; | |
577 | psxRegs.pc = branchPC; | |
578 | ||
579 | psxBranchTest(); | |
580 | } | |
581 | ||
582 | /********************************************************* | |
583 | * Arithmetic with immediate operand * | |
584 | * Format: OP rt, rs, immediate * | |
585 | *********************************************************/ | |
4cc373dd | 586 | OP(psxADDI) { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im (Exception on Integer Overflow) |
587 | OP(psxADDIU) { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im | |
588 | OP(psxANDI) { if (!_Rt_) return; _rRt_ = _u32(_rRs_) & _ImmU_; } // Rt = Rs And Im | |
589 | OP(psxORI) { if (!_Rt_) return; _rRt_ = _u32(_rRs_) | _ImmU_; } // Rt = Rs Or Im | |
590 | OP(psxXORI) { if (!_Rt_) return; _rRt_ = _u32(_rRs_) ^ _ImmU_; } // Rt = Rs Xor Im | |
591 | OP(psxSLTI) { if (!_Rt_) return; _rRt_ = _i32(_rRs_) < _Imm_ ; } // Rt = Rs < Im (Signed) | |
592 | OP(psxSLTIU) { if (!_Rt_) return; _rRt_ = _u32(_rRs_) < ((u32)_Imm_); } // Rt = Rs < Im (Unsigned) | |
ef79bbde P |
593 | |
594 | /********************************************************* | |
595 | * Register arithmetic * | |
596 | * Format: OP rd, rs, rt * | |
597 | *********************************************************/ | |
4cc373dd | 598 | OP(psxADD) { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt (Exception on Integer Overflow) |
599 | OP(psxADDU) { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt | |
600 | OP(psxSUB) { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt (Exception on Integer Overflow) | |
601 | OP(psxSUBU) { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt | |
602 | OP(psxAND) { if (!_Rd_) return; _rRd_ = _u32(_rRs_) & _u32(_rRt_); } // Rd = Rs And Rt | |
603 | OP(psxOR) { if (!_Rd_) return; _rRd_ = _u32(_rRs_) | _u32(_rRt_); } // Rd = Rs Or Rt | |
604 | OP(psxXOR) { if (!_Rd_) return; _rRd_ = _u32(_rRs_) ^ _u32(_rRt_); } // Rd = Rs Xor Rt | |
605 | OP(psxNOR) { if (!_Rd_) return; _rRd_ =~(_u32(_rRs_) | _u32(_rRt_)); }// Rd = Rs Nor Rt | |
606 | OP(psxSLT) { if (!_Rd_) return; _rRd_ = _i32(_rRs_) < _i32(_rRt_); } // Rd = Rs < Rt (Signed) | |
607 | OP(psxSLTU) { if (!_Rd_) return; _rRd_ = _u32(_rRs_) < _u32(_rRt_); } // Rd = Rs < Rt (Unsigned) | |
ef79bbde P |
608 | |
609 | /********************************************************* | |
610 | * Register mult/div & Register trap logic * | |
611 | * Format: OP rs, rt * | |
612 | *********************************************************/ | |
4cc373dd | 613 | OP(psxDIV) { |
614 | if (!_rRt_) { | |
615 | _rHi_ = _rRs_; | |
616 | if (_rRs_ & 0x80000000) { | |
617 | _rLo_ = 1; | |
618 | } else { | |
619 | _rLo_ = 0xFFFFFFFF; | |
620 | } | |
621 | } | |
a4ae3997 | 622 | #if !defined(__arm__) && !defined(__aarch64__) |
4cc373dd | 623 | else if (_rRs_ == 0x80000000 && _rRt_ == 0xFFFFFFFF) { |
624 | _rLo_ = 0x80000000; | |
625 | _rHi_ = 0; | |
626 | } | |
a4ae3997 | 627 | #endif |
4cc373dd | 628 | else { |
629 | _rLo_ = _i32(_rRs_) / _i32(_rRt_); | |
630 | _rHi_ = _i32(_rRs_) % _i32(_rRt_); | |
631 | } | |
ef79bbde P |
632 | } |
633 | ||
4cc373dd | 634 | OP(psxDIV_stall) { |
635 | regs_->muldivBusyCycle = regs_->cycle + 37; | |
636 | psxDIV(regs_, code); | |
32631e6a | 637 | } |
638 | ||
4cc373dd | 639 | OP(psxDIVU) { |
ef79bbde P |
640 | if (_rRt_ != 0) { |
641 | _rLo_ = _rRs_ / _rRt_; | |
642 | _rHi_ = _rRs_ % _rRt_; | |
643 | } | |
c7a56f4f | 644 | else { |
4cc373dd | 645 | _rLo_ = 0xffffffff; |
646 | _rHi_ = _rRs_; | |
c7a56f4f | 647 | } |
ef79bbde P |
648 | } |
649 | ||
4cc373dd | 650 | OP(psxDIVU_stall) { |
651 | regs_->muldivBusyCycle = regs_->cycle + 37; | |
652 | psxDIVU(regs_, code); | |
32631e6a | 653 | } |
654 | ||
4cc373dd | 655 | OP(psxMULT) { |
656 | u64 res = (s64)_i32(_rRs_) * _i32(_rRt_); | |
ef79bbde | 657 | |
4cc373dd | 658 | regs_->GPR.n.lo = (u32)res; |
659 | regs_->GPR.n.hi = (u32)(res >> 32); | |
ef79bbde P |
660 | } |
661 | ||
4cc373dd | 662 | OP(psxMULT_stall) { |
32631e6a | 663 | // approximate, but maybe good enough |
664 | u32 rs = _rRs_; | |
665 | u32 lz = __builtin_clz(((rs ^ ((s32)rs >> 21)) | 1)); | |
666 | u32 c = 7 + (2 - (lz / 11)) * 4; | |
4cc373dd | 667 | regs_->muldivBusyCycle = regs_->cycle + c; |
668 | psxMULT(regs_, code); | |
32631e6a | 669 | } |
670 | ||
4cc373dd | 671 | OP(psxMULTU) { |
672 | u64 res = (u64)_u32(_rRs_) * _u32(_rRt_); | |
ef79bbde | 673 | |
4cc373dd | 674 | regs_->GPR.n.lo = (u32)(res & 0xffffffff); |
675 | regs_->GPR.n.hi = (u32)((res >> 32) & 0xffffffff); | |
ef79bbde P |
676 | } |
677 | ||
4cc373dd | 678 | OP(psxMULTU_stall) { |
32631e6a | 679 | // approximate, but maybe good enough |
680 | u32 lz = __builtin_clz(_rRs_ | 1); | |
681 | u32 c = 7 + (2 - (lz / 11)) * 4; | |
4cc373dd | 682 | regs_->muldivBusyCycle = regs_->cycle + c; |
683 | psxMULTU(regs_, code); | |
32631e6a | 684 | } |
685 | ||
ef79bbde P |
686 | /********************************************************* |
687 | * Register branch logic * | |
688 | * Format: OP rs, offset * | |
689 | *********************************************************/ | |
19fae7fc | 690 | #define RepZBranchi32(op) \ |
691 | if(_i32(_rRs_) op 0) \ | |
692 | doBranch(_BranchTarget_); | |
693 | #define RepZBranchLinki32(op) { \ | |
694 | s32 temp = _i32(_rRs_); \ | |
695 | _SetLink(31); \ | |
696 | if(temp op 0) \ | |
697 | doBranch(_BranchTarget_); \ | |
698 | } | |
ef79bbde | 699 | |
4cc373dd | 700 | OP(psxBGEZ) { RepZBranchi32(>=) } // Branch if Rs >= 0 |
701 | OP(psxBGEZAL) { RepZBranchLinki32(>=) } // Branch if Rs >= 0 and link | |
702 | OP(psxBGTZ) { RepZBranchi32(>) } // Branch if Rs > 0 | |
703 | OP(psxBLEZ) { RepZBranchi32(<=) } // Branch if Rs <= 0 | |
704 | OP(psxBLTZ) { RepZBranchi32(<) } // Branch if Rs < 0 | |
705 | OP(psxBLTZAL) { RepZBranchLinki32(<) } // Branch if Rs < 0 and link | |
ef79bbde P |
706 | |
707 | /********************************************************* | |
708 | * Shift arithmetic with constant shift * | |
709 | * Format: OP rd, rt, sa * | |
710 | *********************************************************/ | |
4cc373dd | 711 | OP(psxSLL) { if (!_Rd_) return; _rRd_ = _u32(_rRt_) << _Sa_; } // Rd = Rt << sa |
712 | OP(psxSRA) { if (!_Rd_) return; _rRd_ = _i32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (arithmetic) | |
713 | OP(psxSRL) { if (!_Rd_) return; _rRd_ = _u32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (logical) | |
ef79bbde P |
714 | |
715 | /********************************************************* | |
716 | * Shift arithmetic with variant register shift * | |
717 | * Format: OP rd, rt, rs * | |
718 | *********************************************************/ | |
4cc373dd | 719 | OP(psxSLLV) { if (!_Rd_) return; _rRd_ = _u32(_rRt_) << (_u32(_rRs_) & 0x1F); } // Rd = Rt << rs |
720 | OP(psxSRAV) { if (!_Rd_) return; _rRd_ = _i32(_rRt_) >> (_u32(_rRs_) & 0x1F); } // Rd = Rt >> rs (arithmetic) | |
721 | OP(psxSRLV) { if (!_Rd_) return; _rRd_ = _u32(_rRt_) >> (_u32(_rRs_) & 0x1F); } // Rd = Rt >> rs (logical) | |
ef79bbde P |
722 | |
723 | /********************************************************* | |
724 | * Load higher 16 bits of the first word in GPR with imm * | |
725 | * Format: OP rt, immediate * | |
726 | *********************************************************/ | |
4cc373dd | 727 | OP(psxLUI) { if (!_Rt_) return; _rRt_ = code << 16; } // Upper halfword of Rt = Im |
ef79bbde P |
728 | |
729 | /********************************************************* | |
730 | * Move from HI/LO to GPR * | |
731 | * Format: OP rd * | |
732 | *********************************************************/ | |
4cc373dd | 733 | OP(psxMFHI) { if (!_Rd_) return; _rRd_ = _rHi_; } // Rd = Hi |
734 | OP(psxMFLO) { if (!_Rd_) return; _rRd_ = _rLo_; } // Rd = Lo | |
ef79bbde | 735 | |
4cc373dd | 736 | static void mflohiCheckStall(psxRegisters *regs_) |
32631e6a | 737 | { |
4cc373dd | 738 | u32 left = regs_->muldivBusyCycle - regs_->cycle; |
32631e6a | 739 | if (left <= 37) { |
740 | //printf("muldiv stall %u\n", left); | |
4cc373dd | 741 | regs_->cycle = regs_->muldivBusyCycle; |
32631e6a | 742 | } |
743 | } | |
744 | ||
4cc373dd | 745 | OP(psxMFHI_stall) { mflohiCheckStall(regs_); psxMFHI(regs_, code); } |
746 | OP(psxMFLO_stall) { mflohiCheckStall(regs_); psxMFLO(regs_, code); } | |
32631e6a | 747 | |
ef79bbde P |
748 | /********************************************************* |
749 | * Move to GPR to HI/LO & Register jump * | |
750 | * Format: OP rs * | |
751 | *********************************************************/ | |
4cc373dd | 752 | OP(psxMTHI) { _rHi_ = _rRs_; } // Hi = Rs |
753 | OP(psxMTLO) { _rLo_ = _rRs_; } // Lo = Rs | |
ef79bbde P |
754 | |
755 | /********************************************************* | |
756 | * Special purpose instructions * | |
757 | * Format: OP * | |
758 | *********************************************************/ | |
4cc373dd | 759 | OP(psxBREAK) { |
760 | regs_->pc -= 4; | |
6d75addf | 761 | psxException(0x24, branch, ®s_->CP0); |
ef79bbde P |
762 | } |
763 | ||
4cc373dd | 764 | OP(psxSYSCALL) { |
765 | regs_->pc -= 4; | |
6d75addf | 766 | psxException(0x20, branch, ®s_->CP0); |
ef79bbde P |
767 | } |
768 | ||
4cc373dd | 769 | static inline void psxTestSWInts(psxRegisters *regs_) { |
770 | if (regs_->CP0.n.Cause & regs_->CP0.n.Status & 0x0300 && | |
771 | regs_->CP0.n.Status & 0x1) { | |
772 | regs_->CP0.n.Cause &= ~0x7c; | |
6d75addf | 773 | psxException(regs_->CP0.n.Cause, branch, ®s_->CP0); |
4cc373dd | 774 | } |
775 | } | |
776 | ||
777 | OP(psxRFE) { | |
ef79bbde | 778 | // SysPrintf("psxRFE\n"); |
4cc373dd | 779 | regs_->CP0.n.Status = (regs_->CP0.n.Status & 0xfffffff0) | |
780 | ((regs_->CP0.n.Status & 0x3c) >> 2); | |
781 | psxTestSWInts(regs_); | |
ef79bbde P |
782 | } |
783 | ||
784 | /********************************************************* | |
785 | * Register branch logic * | |
786 | * Format: OP rs, rt, offset * | |
787 | *********************************************************/ | |
788 | #define RepBranchi32(op) if(_i32(_rRs_) op _i32(_rRt_)) doBranch(_BranchTarget_); | |
789 | ||
4cc373dd | 790 | OP(psxBEQ) { RepBranchi32(==) } // Branch if Rs == Rt |
791 | OP(psxBNE) { RepBranchi32(!=) } // Branch if Rs != Rt | |
ef79bbde P |
792 | |
793 | /********************************************************* | |
794 | * Jump to target * | |
795 | * Format: OP target * | |
796 | *********************************************************/ | |
4cc373dd | 797 | OP(psxJ) { doBranch(_JumpTarget_); } |
798 | OP(psxJAL) { _SetLink(31); doBranch(_JumpTarget_); } | |
ef79bbde P |
799 | |
800 | /********************************************************* | |
801 | * Register jump * | |
802 | * Format: OP rs, rd * | |
803 | *********************************************************/ | |
4cc373dd | 804 | OP(psxJR) { |
943a507a | 805 | doBranch(_rRs_ & ~3); |
ef79bbde P |
806 | psxJumpTest(); |
807 | } | |
808 | ||
4cc373dd | 809 | OP(psxJALR) { |
ef79bbde P |
810 | u32 temp = _u32(_rRs_); |
811 | if (_Rd_) { _SetLink(_Rd_); } | |
943a507a | 812 | doBranch(temp & ~3); |
ef79bbde P |
813 | } |
814 | ||
815 | /********************************************************* | |
816 | * Load and store for GPR * | |
817 | * Format: OP rt, offset(base) * | |
818 | *********************************************************/ | |
819 | ||
4cc373dd | 820 | #define _oB_ (regs_->GPR.r[_Rs_] + _Imm_) |
ef79bbde | 821 | |
4cc373dd | 822 | OP(psxLB) { u32 v = (s8)psxMemRead8(_oB_); if (_Rt_) _rRt_ = v; } |
823 | OP(psxLBU) { u32 v = psxMemRead8(_oB_); if (_Rt_) _rRt_ = v; } | |
824 | OP(psxLH) { u32 v = (s16)psxMemRead16(_oB_); if (_Rt_) _rRt_ = v; } | |
825 | OP(psxLHU) { u32 v = psxMemRead16(_oB_); if (_Rt_) _rRt_ = v; } | |
826 | OP(psxLW) { u32 v = psxMemRead32(_oB_); if (_Rt_) _rRt_ = v; } | |
ef79bbde | 827 | |
4cc373dd | 828 | OP(psxLWL) { |
829 | static const u32 LWL_MASK[4] = { 0xffffff, 0xffff, 0xff, 0 }; | |
830 | static const u32 LWL_SHIFT[4] = { 24, 16, 8, 0 }; | |
ef79bbde P |
831 | u32 addr = _oB_; |
832 | u32 shift = addr & 3; | |
833 | u32 mem = psxMemRead32(addr & ~3); | |
834 | ||
835 | if (!_Rt_) return; | |
4cc373dd | 836 | _rRt_ = (_u32(_rRt_) & LWL_MASK[shift]) | (mem << LWL_SHIFT[shift]); |
ef79bbde P |
837 | |
838 | /* | |
839 | Mem = 1234. Reg = abcd | |
840 | ||
841 | 0 4bcd (mem << 24) | (reg & 0x00ffffff) | |
842 | 1 34cd (mem << 16) | (reg & 0x0000ffff) | |
843 | 2 234d (mem << 8) | (reg & 0x000000ff) | |
844 | 3 1234 (mem ) | (reg & 0x00000000) | |
845 | */ | |
846 | } | |
847 | ||
4cc373dd | 848 | OP(psxLWR) { |
849 | static const u32 LWR_MASK[4] = { 0, 0xff000000, 0xffff0000, 0xffffff00 }; | |
850 | static const u32 LWR_SHIFT[4] = { 0, 8, 16, 24 }; | |
ef79bbde P |
851 | u32 addr = _oB_; |
852 | u32 shift = addr & 3; | |
853 | u32 mem = psxMemRead32(addr & ~3); | |
854 | ||
855 | if (!_Rt_) return; | |
4cc373dd | 856 | _rRt_ = (_u32(_rRt_) & LWR_MASK[shift]) | (mem >> LWR_SHIFT[shift]); |
ef79bbde P |
857 | |
858 | /* | |
859 | Mem = 1234. Reg = abcd | |
860 | ||
861 | 0 1234 (mem ) | (reg & 0x00000000) | |
862 | 1 a123 (mem >> 8) | (reg & 0xff000000) | |
863 | 2 ab12 (mem >> 16) | (reg & 0xffff0000) | |
864 | 3 abc1 (mem >> 24) | (reg & 0xffffff00) | |
865 | */ | |
866 | } | |
867 | ||
4cc373dd | 868 | OP(psxSB) { psxMemWrite8 (_oB_, _rRt_ & 0xff); } |
869 | OP(psxSH) { psxMemWrite16(_oB_, _rRt_ & 0xffff); } | |
870 | OP(psxSW) { psxMemWrite32(_oB_, _rRt_); } | |
ef79bbde | 871 | |
4cc373dd | 872 | OP(psxSWL) { |
873 | static const u32 SWL_MASK[4] = { 0xffffff00, 0xffff0000, 0xff000000, 0 }; | |
874 | static const u32 SWL_SHIFT[4] = { 24, 16, 8, 0 }; | |
ef79bbde P |
875 | u32 addr = _oB_; |
876 | u32 shift = addr & 3; | |
877 | u32 mem = psxMemRead32(addr & ~3); | |
878 | ||
879 | psxMemWrite32(addr & ~3, (_u32(_rRt_) >> SWL_SHIFT[shift]) | | |
880 | ( mem & SWL_MASK[shift]) ); | |
881 | /* | |
882 | Mem = 1234. Reg = abcd | |
883 | ||
884 | 0 123a (reg >> 24) | (mem & 0xffffff00) | |
885 | 1 12ab (reg >> 16) | (mem & 0xffff0000) | |
886 | 2 1abc (reg >> 8) | (mem & 0xff000000) | |
887 | 3 abcd (reg ) | (mem & 0x00000000) | |
888 | */ | |
889 | } | |
890 | ||
4cc373dd | 891 | OP(psxSWR) { |
892 | static const u32 SWR_MASK[4] = { 0, 0xff, 0xffff, 0xffffff }; | |
893 | static const u32 SWR_SHIFT[4] = { 0, 8, 16, 24 }; | |
ef79bbde P |
894 | u32 addr = _oB_; |
895 | u32 shift = addr & 3; | |
896 | u32 mem = psxMemRead32(addr & ~3); | |
897 | ||
898 | psxMemWrite32(addr & ~3, (_u32(_rRt_) << SWR_SHIFT[shift]) | | |
899 | ( mem & SWR_MASK[shift]) ); | |
900 | ||
901 | /* | |
902 | Mem = 1234. Reg = abcd | |
903 | ||
904 | 0 abcd (reg ) | (mem & 0x00000000) | |
905 | 1 bcd4 (reg << 8) | (mem & 0x000000ff) | |
906 | 2 cd34 (reg << 16) | (mem & 0x0000ffff) | |
907 | 3 d234 (reg << 24) | (mem & 0x00ffffff) | |
908 | */ | |
909 | } | |
910 | ||
911 | /********************************************************* | |
912 | * Moves between GPR and COPx * | |
913 | * Format: OP rt, fs * | |
914 | *********************************************************/ | |
4cc373dd | 915 | OP(psxMFC0) { if (!_Rt_) return; _rRt_ = _rFs_; } |
916 | OP(psxCFC0) { if (!_Rt_) return; _rRt_ = _rFs_; } | |
ef79bbde | 917 | |
4cc373dd | 918 | void MTC0(psxRegisters *regs_, int reg, u32 val) { |
ef79bbde P |
919 | // SysPrintf("MTC0 %d: %x\n", reg, val); |
920 | switch (reg) { | |
921 | case 12: // Status | |
679d5ee3 | 922 | if ((regs_->CP0.n.Status ^ val) & (1 << 16)) |
923 | psxMemOnIsolate((val >> 16) & 1); | |
924 | regs_->CP0.n.Status = val; | |
4cc373dd | 925 | psxTestSWInts(regs_); |
ef79bbde P |
926 | break; |
927 | ||
928 | case 13: // Cause | |
4cc373dd | 929 | regs_->CP0.n.Cause &= ~0x0300; |
930 | regs_->CP0.n.Cause |= val & 0x0300; | |
931 | psxTestSWInts(regs_); | |
ef79bbde P |
932 | break; |
933 | ||
934 | default: | |
4cc373dd | 935 | regs_->CP0.r[reg] = val; |
ef79bbde P |
936 | break; |
937 | } | |
938 | } | |
939 | ||
4cc373dd | 940 | OP(psxMTC0) { MTC0(regs_, _Rd_, _u32(_rRt_)); } |
941 | OP(psxCTC0) { MTC0(regs_, _Rd_, _u32(_rRt_)); } | |
ef79bbde P |
942 | |
943 | /********************************************************* | |
944 | * Unknow instruction (would generate an exception) * | |
945 | * Format: ? * | |
946 | *********************************************************/ | |
4cc373dd | 947 | static inline void psxNULL_(void) { |
ef79bbde P |
948 | #ifdef PSXCPU_LOG |
949 | PSXCPU_LOG("psx: Unimplemented op %x\n", psxRegs.code); | |
950 | #endif | |
951 | } | |
952 | ||
4cc373dd | 953 | OP(psxNULL) { psxNULL_(); } |
954 | void gteNULL(struct psxCP2Regs *regs) { psxNULL_(); } | |
ef79bbde | 955 | |
4cc373dd | 956 | OP(psxSPECIAL) { |
957 | psxSPC[_Funct_](regs_, code); | |
ef79bbde P |
958 | } |
959 | ||
4cc373dd | 960 | OP(psxCOP0) { |
961 | switch (_Rs_) { | |
962 | case 0x00: psxMFC0(regs_, code); break; | |
963 | case 0x02: psxCFC0(regs_, code); break; | |
964 | case 0x04: psxMTC0(regs_, code); break; | |
965 | case 0x06: psxCTC0(regs_, code); break; | |
966 | case 0x10: psxRFE(regs_, code); break; | |
967 | default: psxNULL_(); break; | |
968 | } | |
ef79bbde P |
969 | } |
970 | ||
4cc373dd | 971 | OP(psxCOP2) { |
972 | psxCP2[_Funct_](®s_->CP2); | |
32631e6a | 973 | } |
974 | ||
4cc373dd | 975 | OP(psxCOP2_stall) { |
81dbbf4c | 976 | u32 f = _Funct_; |
32631e6a | 977 | gteCheckStall(f); |
4cc373dd | 978 | psxCP2[f](®s_->CP2); |
979 | } | |
980 | ||
981 | OP(gteMFC2) { | |
982 | if (!_Rt_) return; | |
983 | regs_->GPR.r[_Rt_] = MFC2(®s_->CP2, _Rd_); | |
984 | } | |
985 | ||
986 | OP(gteCFC2) { | |
987 | if (!_Rt_) return; | |
988 | regs_->GPR.r[_Rt_] = regs_->CP2C.r[_Rd_]; | |
989 | } | |
990 | ||
991 | OP(gteMTC2) { | |
992 | MTC2(®s_->CP2, regs_->GPR.r[_Rt_], _Rd_); | |
993 | } | |
994 | ||
995 | OP(gteCTC2) { | |
996 | CTC2(®s_->CP2, regs_->GPR.r[_Rt_], _Rd_); | |
997 | } | |
998 | ||
999 | OP(gteLWC2) { | |
1000 | MTC2(®s_->CP2, psxMemRead32(_oB_), _Rt_); | |
1001 | } | |
1002 | ||
1003 | OP(gteSWC2) { | |
1004 | psxMemWrite32(_oB_, MFC2(®s_->CP2, _Rt_)); | |
1005 | } | |
1006 | ||
1007 | OP(gteLWC2_stall) { | |
1008 | gteCheckStall(0); | |
1009 | gteLWC2(regs_, code); | |
ef79bbde P |
1010 | } |
1011 | ||
4cc373dd | 1012 | OP(gteSWC2_stall) { |
1013 | gteCheckStall(0); | |
1014 | gteSWC2(regs_, code); | |
1015 | } | |
1016 | ||
1017 | static void psxBASIC(struct psxCP2Regs *cp2regs) { | |
1018 | psxRegisters *regs_ = (void *)((char *)cp2regs - offsetof(psxRegisters, CP2)); | |
1019 | u32 code = regs_->code; | |
1020 | assert(regs_ == &psxRegs); | |
1021 | switch (_Rs_) { | |
1022 | case 0x00: gteMFC2(regs_, code); break; | |
1023 | case 0x02: gteCFC2(regs_, code); break; | |
1024 | case 0x04: gteMTC2(regs_, code); break; | |
1025 | case 0x06: gteCTC2(regs_, code); break; | |
1026 | default: psxNULL_(); break; | |
1027 | } | |
1028 | } | |
1029 | ||
1030 | OP(psxREGIMM) { | |
19fae7fc | 1031 | u32 rt = _Rt_; |
1032 | switch (rt) { | |
4cc373dd | 1033 | case 0x10: psxBLTZAL(regs_, code); break; |
1034 | case 0x11: psxBGEZAL(regs_, code); break; | |
19fae7fc | 1035 | default: |
1036 | if (rt & 1) | |
1037 | psxBGEZ(regs_, code); | |
1038 | else | |
1039 | psxBLTZ(regs_, code); | |
4cc373dd | 1040 | } |
ef79bbde P |
1041 | } |
1042 | ||
4cc373dd | 1043 | OP(psxHLE) { |
1044 | uint32_t hleCode = code & 0x03ffffff; | |
dd79da89 | 1045 | if (hleCode >= (sizeof(psxHLEt) / sizeof(psxHLEt[0]))) { |
4cc373dd | 1046 | psxNULL_(); |
dd79da89 | 1047 | } else { |
1048 | psxHLEt[hleCode](); | |
1049 | } | |
ef79bbde P |
1050 | } |
1051 | ||
4cc373dd | 1052 | static void (INT_ATTR *psxBSC[64])(psxRegisters *regs_, u32 code) = { |
ef79bbde P |
1053 | psxSPECIAL, psxREGIMM, psxJ , psxJAL , psxBEQ , psxBNE , psxBLEZ, psxBGTZ, |
1054 | psxADDI , psxADDIU , psxSLTI, psxSLTIU, psxANDI, psxORI , psxXORI, psxLUI , | |
1055 | psxCOP0 , psxNULL , psxCOP2, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, | |
1056 | psxNULL , psxNULL , psxNULL, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, | |
1057 | psxLB , psxLH , psxLWL , psxLW , psxLBU , psxLHU , psxLWR , psxNULL, | |
1058 | psxSB , psxSH , psxSWL , psxSW , psxNULL, psxNULL, psxSWR , psxNULL, | |
1059 | psxNULL , psxNULL , gteLWC2, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, | |
1060 | psxNULL , psxNULL , gteSWC2, psxHLE , psxNULL, psxNULL, psxNULL, psxNULL | |
1061 | }; | |
1062 | ||
4cc373dd | 1063 | static void (INT_ATTR *psxSPC[64])(psxRegisters *regs_, u32 code) = { |
ef79bbde P |
1064 | psxSLL , psxNULL , psxSRL , psxSRA , psxSLLV , psxNULL , psxSRLV, psxSRAV, |
1065 | psxJR , psxJALR , psxNULL, psxNULL, psxSYSCALL, psxBREAK, psxNULL, psxNULL, | |
1066 | psxMFHI, psxMTHI , psxMFLO, psxMTLO, psxNULL , psxNULL , psxNULL, psxNULL, | |
1067 | psxMULT, psxMULTU, psxDIV , psxDIVU, psxNULL , psxNULL , psxNULL, psxNULL, | |
1068 | psxADD , psxADDU , psxSUB , psxSUBU, psxAND , psxOR , psxXOR , psxNOR , | |
1069 | psxNULL, psxNULL , psxSLT , psxSLTU, psxNULL , psxNULL , psxNULL, psxNULL, | |
1070 | psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL, | |
1071 | psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL | |
1072 | }; | |
1073 | ||
6c0eefaf | 1074 | void (*psxCP2[64])(struct psxCP2Regs *regs) = { |
4cc373dd | 1075 | psxBASIC, gteRTPS , gteNULL , gteNULL, gteNULL, gteNULL , gteNCLIP, gteNULL, // 00 |
1076 | gteNULL , gteNULL , gteNULL , gteNULL, gteOP , gteNULL , gteNULL , gteNULL, // 08 | |
1077 | gteDPCS , gteINTPL, gteMVMVA, gteNCDS, gteCDP , gteNULL , gteNCDT , gteNULL, // 10 | |
1078 | gteNULL , gteNULL , gteNULL , gteNCCS, gteCC , gteNULL , gteNCS , gteNULL, // 18 | |
1079 | gteNCT , gteNULL , gteNULL , gteNULL, gteNULL, gteNULL , gteNULL , gteNULL, // 20 | |
1080 | gteSQR , gteDCPL , gteDPCT , gteNULL, gteNULL, gteAVSZ3, gteAVSZ4, gteNULL, // 28 | |
1081 | gteRTPT , gteNULL , gteNULL , gteNULL, gteNULL, gteNULL , gteNULL , gteNULL, // 30 | |
1082 | gteNULL , gteNULL , gteNULL , gteNULL, gteNULL, gteGPF , gteGPL , gteNCCT // 38 | |
ef79bbde P |
1083 | }; |
1084 | ||
ef79bbde P |
1085 | /////////////////////////////////////////// |
1086 | ||
1087 | static int intInit() { | |
1088 | return 0; | |
1089 | } | |
1090 | ||
1091 | static void intReset() { | |
1092 | } | |
1093 | ||
4cc373dd | 1094 | static inline void execI_(u8 **memRLUT, psxRegisters *regs_) { |
1095 | regs_->code = fetch(memRLUT, regs_->pc); | |
1096 | ||
1097 | debugI(); | |
1098 | ||
1099 | if (Config.Debug) ProcessDebug(); | |
1100 | ||
1101 | regs_->pc += 4; | |
d5aeda23 | 1102 | addCycle(); |
4cc373dd | 1103 | |
1104 | psxBSC[regs_->code >> 26](regs_, regs_->code); | |
1105 | } | |
1106 | ||
1107 | static void intExecute() { | |
1108 | psxRegisters *regs_ = &psxRegs; | |
1109 | u8 **memRLUT = psxMemRLUT; | |
796a91ef | 1110 | extern int stop; |
4cc373dd | 1111 | |
1112 | while (!stop) | |
1113 | execI_(memRLUT, regs_); | |
ef79bbde P |
1114 | } |
1115 | ||
da65071f | 1116 | void intExecuteBlock(enum blockExecCaller caller) { |
4cc373dd | 1117 | psxRegisters *regs_ = &psxRegs; |
1118 | u8 **memRLUT = psxMemRLUT; | |
1119 | ||
ef79bbde | 1120 | branch2 = 0; |
4cc373dd | 1121 | while (!branch2) |
1122 | execI_(memRLUT, regs_); | |
ef79bbde P |
1123 | } |
1124 | ||
1125 | static void intClear(u32 Addr, u32 Size) { | |
1126 | } | |
1127 | ||
980f7a58 | 1128 | static void intNotify(enum R3000Anote note, void *data) { |
1129 | switch (note) { | |
1130 | case R3000ACPU_NOTIFY_CACHE_ISOLATED: // Armored Core? | |
1131 | case R3000ACPU_NOTIFY_AFTER_LOAD: | |
9f84fc93 | 1132 | memset(&ICache, 0xff, sizeof(ICache)); |
980f7a58 | 1133 | break; |
1134 | case R3000ACPU_NOTIFY_CACHE_UNISOLATED: | |
1135 | case R3000ACPU_NOTIFY_BEFORE_SAVE: | |
1136 | break; | |
943a507a | 1137 | } |
943a507a | 1138 | } |
1139 | ||
61ad2a61 | 1140 | void intApplyConfig() { |
d5aeda23 | 1141 | int cycle_mult; |
1142 | ||
32631e6a | 1143 | assert(psxBSC[18] == psxCOP2 || psxBSC[18] == psxCOP2_stall); |
1144 | assert(psxBSC[50] == gteLWC2 || psxBSC[50] == gteLWC2_stall); | |
1145 | assert(psxBSC[58] == gteSWC2 || psxBSC[58] == gteSWC2_stall); | |
1146 | assert(psxSPC[16] == psxMFHI || psxSPC[16] == psxMFHI_stall); | |
1147 | assert(psxSPC[18] == psxMFLO || psxSPC[18] == psxMFLO_stall); | |
1148 | assert(psxSPC[24] == psxMULT || psxSPC[24] == psxMULT_stall); | |
1149 | assert(psxSPC[25] == psxMULTU || psxSPC[25] == psxMULTU_stall); | |
1150 | assert(psxSPC[26] == psxDIV || psxSPC[26] == psxDIV_stall); | |
1151 | assert(psxSPC[27] == psxDIVU || psxSPC[27] == psxDIVU_stall); | |
1152 | ||
1153 | if (Config.DisableStalls) { | |
1154 | psxBSC[18] = psxCOP2; | |
1155 | psxBSC[50] = gteLWC2; | |
1156 | psxBSC[58] = gteSWC2; | |
1157 | psxSPC[16] = psxMFHI; | |
1158 | psxSPC[18] = psxMFLO; | |
1159 | psxSPC[24] = psxMULT; | |
1160 | psxSPC[25] = psxMULTU; | |
1161 | psxSPC[26] = psxDIV; | |
1162 | psxSPC[27] = psxDIVU; | |
1163 | } else { | |
1164 | psxBSC[18] = psxCOP2_stall; | |
1165 | psxBSC[50] = gteLWC2_stall; | |
1166 | psxBSC[58] = gteSWC2_stall; | |
1167 | psxSPC[16] = psxMFHI_stall; | |
1168 | psxSPC[18] = psxMFLO_stall; | |
1169 | psxSPC[24] = psxMULT_stall; | |
1170 | psxSPC[25] = psxMULTU_stall; | |
1171 | psxSPC[26] = psxDIV_stall; | |
1172 | psxSPC[27] = psxDIVU_stall; | |
1173 | } | |
61ad2a61 | 1174 | |
1175 | // dynarec may occasionally call the interpreter, in such a case the | |
1176 | // cache won't work (cache only works right if all fetches go through it) | |
1177 | if (!Config.icache_emulation || psxCpu != &psxInt) | |
1178 | fetch = fetchNoCache; | |
1179 | else | |
1180 | fetch = fetchICache; | |
d5aeda23 | 1181 | |
1182 | cycle_mult = Config.cycle_multiplier_override && Config.cycle_multiplier == CYCLE_MULT_DEFAULT | |
1183 | ? Config.cycle_multiplier_override : Config.cycle_multiplier; | |
1184 | psxRegs.subCycleStep = 0x10000 * cycle_mult / 100; | |
32631e6a | 1185 | } |
1186 | ||
ef79bbde P |
1187 | static void intShutdown() { |
1188 | } | |
1189 | ||
4cc373dd | 1190 | // single step (may do several ops in case of a branch) |
4600ba03 | 1191 | void execI() { |
4cc373dd | 1192 | execI_(psxMemRLUT, &psxRegs); |
ef79bbde P |
1193 | } |
1194 | ||
1195 | R3000Acpu psxInt = { | |
1196 | intInit, | |
1197 | intReset, | |
1198 | intExecute, | |
1199 | intExecuteBlock, | |
1200 | intClear, | |
943a507a | 1201 | intNotify, |
61ad2a61 | 1202 | intApplyConfig, |
ef79bbde P |
1203 | intShutdown |
1204 | }; |