Fix detection of some CDs such as Wild Arms USA detected as a PAL game. (#222)
[pcsx_rearmed.git] / libpcsxcore / psxinterpreter.c
CommitLineData
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"
fc8145b7 28#include "debug.h"
ef79bbde
P
29
30static int branch = 0;
31static int branch2 = 0;
32static u32 branchPC;
33
34// These macros are used to assemble the repassembler functions
35
36#ifdef PSXCPU_LOG
37#define debugI() PSXCPU_LOG("%s\n", disR3000AF(psxRegs.code, psxRegs.pc));
38#else
39#define debugI()
40#endif
41
4600ba03 42void execI();
ef79bbde
P
43
44// Subsets
45void (*psxBSC[64])();
46void (*psxSPC[64])();
47void (*psxREG[32])();
48void (*psxCP0[32])();
6c0eefaf 49void (*psxCP2[64])(struct psxCP2Regs *regs);
ef79bbde
P
50void (*psxCP2BSC[32])();
51
52static void delayRead(int reg, u32 bpc) {
53 u32 rold, rnew;
54
55// SysPrintf("delayRead at %x!\n", psxRegs.pc);
56
57 rold = psxRegs.GPR.r[reg];
58 psxBSC[psxRegs.code >> 26](); // branch delay load
59 rnew = psxRegs.GPR.r[reg];
60
61 psxRegs.pc = bpc;
62
abbc1ca1 63 branch = 0;
ef79bbde
P
64
65 psxRegs.GPR.r[reg] = rold;
66 execI(); // first branch opcode
67 psxRegs.GPR.r[reg] = rnew;
68
abbc1ca1 69 psxBranchTest();
ef79bbde
P
70}
71
72static void delayWrite(int reg, u32 bpc) {
73
74/* SysPrintf("delayWrite at %x!\n", psxRegs.pc);
75
76 SysPrintf("%s\n", disR3000AF(psxRegs.code, psxRegs.pc-4));
77 SysPrintf("%s\n", disR3000AF(PSXMu32(bpc), bpc));*/
78
79 // no changes from normal behavior
80
81 psxBSC[psxRegs.code >> 26]();
82
83 branch = 0;
84 psxRegs.pc = bpc;
85
86 psxBranchTest();
87}
88
89static void delayReadWrite(int reg, u32 bpc) {
90
91// SysPrintf("delayReadWrite at %x!\n", psxRegs.pc);
92
93 // the branch delay load is skipped
94
95 branch = 0;
96 psxRegs.pc = bpc;
97
98 psxBranchTest();
99}
100
101// this defines shall be used with the tmp
102// of the next func (instead of _Funct_...)
103#define _tFunct_ ((tmp ) & 0x3F) // The funct part of the instruction register
104#define _tRd_ ((tmp >> 11) & 0x1F) // The rd part of the instruction register
105#define _tRt_ ((tmp >> 16) & 0x1F) // The rt part of the instruction register
106#define _tRs_ ((tmp >> 21) & 0x1F) // The rs part of the instruction register
107#define _tSa_ ((tmp >> 6) & 0x1F) // The sa part of the instruction register
108
109int psxTestLoadDelay(int reg, u32 tmp) {
110 if (tmp == 0) return 0; // NOP
111 switch (tmp >> 26) {
112 case 0x00: // SPECIAL
113 switch (_tFunct_) {
114 case 0x00: // SLL
115 case 0x02: case 0x03: // SRL/SRA
116 if (_tRd_ == reg && _tRt_ == reg) return 1; else
117 if (_tRt_ == reg) return 2; else
118 if (_tRd_ == reg) return 3;
119 break;
120
121 case 0x08: // JR
122 if (_tRs_ == reg) return 2;
123 break;
124 case 0x09: // JALR
125 if (_tRd_ == reg && _tRs_ == reg) return 1; else
126 if (_tRs_ == reg) return 2; else
127 if (_tRd_ == reg) return 3;
128 break;
129
130 // SYSCALL/BREAK just a break;
131
132 case 0x20: case 0x21: case 0x22: case 0x23:
133 case 0x24: case 0x25: case 0x26: case 0x27:
134 case 0x2a: case 0x2b: // ADD/ADDU...
135 case 0x04: case 0x06: case 0x07: // SLLV...
136 if (_tRd_ == reg && (_tRt_ == reg || _tRs_ == reg)) return 1; else
137 if (_tRt_ == reg || _tRs_ == reg) return 2; else
138 if (_tRd_ == reg) return 3;
139 break;
140
141 case 0x10: case 0x12: // MFHI/MFLO
142 if (_tRd_ == reg) return 3;
143 break;
144 case 0x11: case 0x13: // MTHI/MTLO
145 if (_tRs_ == reg) return 2;
146 break;
147
148 case 0x18: case 0x19:
149 case 0x1a: case 0x1b: // MULT/DIV...
150 if (_tRt_ == reg || _tRs_ == reg) return 2;
151 break;
152 }
153 break;
154
155 case 0x01: // REGIMM
156 switch (_tRt_) {
862bfc0d 157 case 0x00: case 0x01:
158 case 0x10: case 0x11: // BLTZ/BGEZ...
159 // Xenogears - lbu v0 / beq v0
160 // - no load delay (fixes battle loading)
161 break;
162
ef79bbde
P
163 if (_tRs_ == reg) return 2;
164 break;
165 }
166 break;
167
168 // J would be just a break;
169 case 0x03: // JAL
170 if (31 == reg) return 3;
171 break;
172
173 case 0x04: case 0x05: // BEQ/BNE
862bfc0d 174 // Xenogears - lbu v0 / beq v0
175 // - no load delay (fixes battle loading)
176 break;
177
ef79bbde
P
178 if (_tRs_ == reg || _tRt_ == reg) return 2;
179 break;
180
181 case 0x06: case 0x07: // BLEZ/BGTZ
862bfc0d 182 // Xenogears - lbu v0 / beq v0
183 // - no load delay (fixes battle loading)
184 break;
185
ef79bbde
P
186 if (_tRs_ == reg) return 2;
187 break;
188
189 case 0x08: case 0x09: case 0x0a: case 0x0b:
190 case 0x0c: case 0x0d: case 0x0e: // ADDI/ADDIU...
191 if (_tRt_ == reg && _tRs_ == reg) return 1; else
192 if (_tRs_ == reg) return 2; else
193 if (_tRt_ == reg) return 3;
194 break;
195
196 case 0x0f: // LUI
197 if (_tRt_ == reg) return 3;
198 break;
199
200 case 0x10: // COP0
201 switch (_tFunct_) {
202 case 0x00: // MFC0
203 if (_tRt_ == reg) return 3;
204 break;
205 case 0x02: // CFC0
206 if (_tRt_ == reg) return 3;
207 break;
208 case 0x04: // MTC0
209 if (_tRt_ == reg) return 2;
210 break;
211 case 0x06: // CTC0
212 if (_tRt_ == reg) return 2;
213 break;
214 // RFE just a break;
215 }
216 break;
217
218 case 0x12: // COP2
219 switch (_tFunct_) {
220 case 0x00:
221 switch (_tRs_) {
222 case 0x00: // MFC2
223 if (_tRt_ == reg) return 3;
224 break;
225 case 0x02: // CFC2
226 if (_tRt_ == reg) return 3;
227 break;
228 case 0x04: // MTC2
229 if (_tRt_ == reg) return 2;
230 break;
231 case 0x06: // CTC2
232 if (_tRt_ == reg) return 2;
233 break;
234 }
235 break;
236 // RTPS... break;
237 }
238 break;
239
240 case 0x22: case 0x26: // LWL/LWR
241 if (_tRt_ == reg) return 3; else
242 if (_tRs_ == reg) return 2;
243 break;
244
245 case 0x20: case 0x21: case 0x23:
246 case 0x24: case 0x25: // LB/LH/LW/LBU/LHU
247 if (_tRt_ == reg && _tRs_ == reg) return 1; else
248 if (_tRs_ == reg) return 2; else
249 if (_tRt_ == reg) return 3;
250 break;
251
252 case 0x28: case 0x29: case 0x2a:
253 case 0x2b: case 0x2e: // SB/SH/SWL/SW/SWR
254 if (_tRt_ == reg || _tRs_ == reg) return 2;
255 break;
256
257 case 0x32: case 0x3a: // LWC2/SWC2
258 if (_tRs_ == reg) return 2;
259 break;
260 }
261
262 return 0;
263}
264
265void psxDelayTest(int reg, u32 bpc) {
266 u32 *code;
267 u32 tmp;
268
269 code = (u32 *)PSXM(bpc);
270 tmp = ((code == NULL) ? 0 : SWAP32(*code));
271 branch = 1;
272
273 switch (psxTestLoadDelay(reg, tmp)) {
274 case 1:
275 delayReadWrite(reg, bpc); return;
276 case 2:
277 delayRead(reg, bpc); return;
278 case 3:
279 delayWrite(reg, bpc); return;
280 }
281 psxBSC[psxRegs.code >> 26]();
282
283 branch = 0;
284 psxRegs.pc = bpc;
285
286 psxBranchTest();
287}
288
990cb018 289static u32 psxBranchNoDelay(void) {
290 u32 *code;
291 u32 temp;
292
293 code = (u32 *)PSXM(psxRegs.pc);
294 psxRegs.code = ((code == NULL) ? 0 : SWAP32(*code));
295 switch (_Op_) {
296 case 0x00: // SPECIAL
297 switch (_Funct_) {
298 case 0x08: // JR
299 return _u32(_rRs_);
300 case 0x09: // JALR
301 temp = _u32(_rRs_);
302 if (_Rd_) { _SetLink(_Rd_); }
303 return temp;
304 }
305 break;
306 case 0x01: // REGIMM
307 switch (_Rt_) {
308 case 0x00: // BLTZ
309 if (_i32(_rRs_) < 0)
310 return _BranchTarget_;
311 break;
312 case 0x01: // BGEZ
313 if (_i32(_rRs_) >= 0)
314 return _BranchTarget_;
315 break;
316 case 0x08: // BLTZAL
317 if (_i32(_rRs_) < 0) {
318 _SetLink(31);
319 return _BranchTarget_;
320 }
321 break;
322 case 0x09: // BGEZAL
323 if (_i32(_rRs_) >= 0) {
324 _SetLink(31);
325 return _BranchTarget_;
326 }
327 break;
328 }
329 break;
330 case 0x02: // J
331 return _JumpTarget_;
332 case 0x03: // JAL
333 _SetLink(31);
334 return _JumpTarget_;
335 case 0x04: // BEQ
336 if (_i32(_rRs_) == _i32(_rRt_))
337 return _BranchTarget_;
338 break;
339 case 0x05: // BNE
340 if (_i32(_rRs_) != _i32(_rRt_))
341 return _BranchTarget_;
342 break;
343 case 0x06: // BLEZ
344 if (_i32(_rRs_) <= 0)
345 return _BranchTarget_;
346 break;
347 case 0x07: // BGTZ
348 if (_i32(_rRs_) > 0)
349 return _BranchTarget_;
350 break;
351 }
352
353 return (u32)-1;
354}
355
356static int psxDelayBranchExec(u32 tar) {
357 execI();
358
359 branch = 0;
360 psxRegs.pc = tar;
361 psxRegs.cycle += BIAS;
362 psxBranchTest();
363 return 1;
364}
365
366static int psxDelayBranchTest(u32 tar1) {
367 u32 tar2, tmp1, tmp2;
368
369 tar2 = psxBranchNoDelay();
370 if (tar2 == (u32)-1)
371 return 0;
372
373 debugI();
374
375 /*
376 * Branch in delay slot:
377 * - execute 1 instruction at tar1
378 * - jump to tar2 (target of branch in delay slot; this branch
379 * has no normal delay slot, instruction at tar1 was fetched instead)
380 */
381 psxRegs.pc = tar1;
382 tmp1 = psxBranchNoDelay();
383 if (tmp1 == (u32)-1) {
384 return psxDelayBranchExec(tar2);
385 }
386 debugI();
387 psxRegs.cycle += BIAS;
388
389 /*
390 * Got a branch at tar1:
391 * - execute 1 instruction at tar2
392 * - jump to target of that branch (tmp1)
393 */
394 psxRegs.pc = tar2;
395 tmp2 = psxBranchNoDelay();
396 if (tmp2 == (u32)-1) {
397 return psxDelayBranchExec(tmp1);
398 }
399 debugI();
400 psxRegs.cycle += BIAS;
401
402 /*
403 * Got a branch at tar2:
404 * - execute 1 instruction at tmp1
405 * - jump to target of that branch (tmp2)
406 */
407 psxRegs.pc = tmp1;
408 return psxDelayBranchExec(tmp2);
409}
410
4600ba03 411static void doBranch(u32 tar) {
ef79bbde
P
412 u32 *code;
413 u32 tmp;
414
415 branch2 = branch = 1;
416 branchPC = tar;
417
990cb018 418 // check for branch in delay slot
419 if (psxDelayBranchTest(tar))
420 return;
421
ef79bbde
P
422 code = (u32 *)PSXM(psxRegs.pc);
423 psxRegs.code = ((code == NULL) ? 0 : SWAP32(*code));
424
425 debugI();
426
427 psxRegs.pc += 4;
428 psxRegs.cycle += BIAS;
429
430 // check for load delay
431 tmp = psxRegs.code >> 26;
432 switch (tmp) {
433 case 0x10: // COP0
434 switch (_Rs_) {
435 case 0x00: // MFC0
436 case 0x02: // CFC0
437 psxDelayTest(_Rt_, branchPC);
438 return;
439 }
440 break;
441 case 0x12: // COP2
442 switch (_Funct_) {
443 case 0x00:
444 switch (_Rs_) {
445 case 0x00: // MFC2
446 case 0x02: // CFC2
447 psxDelayTest(_Rt_, branchPC);
448 return;
449 }
450 break;
451 }
452 break;
453 case 0x32: // LWC2
454 psxDelayTest(_Rt_, branchPC);
455 return;
456 default:
457 if (tmp >= 0x20 && tmp <= 0x26) { // LB/LH/LWL/LW/LBU/LHU/LWR
458 psxDelayTest(_Rt_, branchPC);
459 return;
460 }
461 break;
462 }
463
464 psxBSC[psxRegs.code >> 26]();
465
466 branch = 0;
467 psxRegs.pc = branchPC;
468
469 psxBranchTest();
470}
471
472/*********************************************************
473* Arithmetic with immediate operand *
474* Format: OP rt, rs, immediate *
475*********************************************************/
476void psxADDI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im (Exception on Integer Overflow)
477void psxADDIU() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im
478void psxANDI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) & _ImmU_; } // Rt = Rs And Im
479void psxORI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) | _ImmU_; } // Rt = Rs Or Im
480void psxXORI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) ^ _ImmU_; } // Rt = Rs Xor Im
481void psxSLTI() { if (!_Rt_) return; _rRt_ = _i32(_rRs_) < _Imm_ ; } // Rt = Rs < Im (Signed)
482void psxSLTIU() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) < ((u32)_Imm_); } // Rt = Rs < Im (Unsigned)
483
484/*********************************************************
485* Register arithmetic *
486* Format: OP rd, rs, rt *
487*********************************************************/
488void psxADD() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt (Exception on Integer Overflow)
489void psxADDU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt
490void psxSUB() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt (Exception on Integer Overflow)
491void psxSUBU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt
492void psxAND() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) & _u32(_rRt_); } // Rd = Rs And Rt
493void psxOR() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) | _u32(_rRt_); } // Rd = Rs Or Rt
494void psxXOR() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) ^ _u32(_rRt_); } // Rd = Rs Xor Rt
495void psxNOR() { if (!_Rd_) return; _rRd_ =~(_u32(_rRs_) | _u32(_rRt_)); }// Rd = Rs Nor Rt
496void psxSLT() { if (!_Rd_) return; _rRd_ = _i32(_rRs_) < _i32(_rRt_); } // Rd = Rs < Rt (Signed)
497void psxSLTU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) < _u32(_rRt_); } // Rd = Rs < Rt (Unsigned)
498
499/*********************************************************
500* Register mult/div & Register trap logic *
501* Format: OP rs, rt *
502*********************************************************/
503void psxDIV() {
a4ae3997 504 if (!_i32(_rRt_)) {
505 _i32(_rHi_) = _i32(_rRs_);
506 if (_i32(_rRs_) & 0x80000000) {
507 _i32(_rLo_) = 1;
508 } else {
509 _i32(_rLo_) = 0xFFFFFFFF;
510 }
511/*
512 * Notaz said that this was "not needed" for ARM platforms and could slow it down so let's disable for ARM.
513 * This fixes a crash issue that can happen when running Amidog's CPU test.
514 * (It still stays stuck to a black screen but at least it doesn't crash anymore)
515 */
516#if !defined(__arm__) && !defined(__aarch64__)
517 } else if (_i32(_rRs_) == 0x80000000 && _i32(_rRt_) == 0xFFFFFFFF) {
518 _i32(_rLo_) = 0x80000000;
519 _i32(_rHi_) = 0;
520#endif
521 } else {
522 _i32(_rLo_) = _i32(_rRs_) / _i32(_rRt_);
523 _i32(_rHi_) = _i32(_rRs_) % _i32(_rRt_);
524 }
ef79bbde
P
525}
526
527void psxDIVU() {
528 if (_rRt_ != 0) {
529 _rLo_ = _rRs_ / _rRt_;
530 _rHi_ = _rRs_ % _rRt_;
531 }
c7a56f4f 532 else {
533 _i32(_rLo_) = 0xffffffff;
534 _i32(_rHi_) = _i32(_rRs_);
535 }
ef79bbde
P
536}
537
538void psxMULT() {
539 u64 res = (s64)((s64)_i32(_rRs_) * (s64)_i32(_rRt_));
540
541 psxRegs.GPR.n.lo = (u32)(res & 0xffffffff);
542 psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff);
543}
544
545void psxMULTU() {
546 u64 res = (u64)((u64)_u32(_rRs_) * (u64)_u32(_rRt_));
547
548 psxRegs.GPR.n.lo = (u32)(res & 0xffffffff);
549 psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff);
550}
551
552/*********************************************************
553* Register branch logic *
554* Format: OP rs, offset *
555*********************************************************/
556#define RepZBranchi32(op) if(_i32(_rRs_) op 0) doBranch(_BranchTarget_);
557#define RepZBranchLinki32(op) if(_i32(_rRs_) op 0) { _SetLink(31); doBranch(_BranchTarget_); }
558
559void psxBGEZ() { RepZBranchi32(>=) } // Branch if Rs >= 0
560void psxBGEZAL() { RepZBranchLinki32(>=) } // Branch if Rs >= 0 and link
561void psxBGTZ() { RepZBranchi32(>) } // Branch if Rs > 0
562void psxBLEZ() { RepZBranchi32(<=) } // Branch if Rs <= 0
563void psxBLTZ() { RepZBranchi32(<) } // Branch if Rs < 0
564void psxBLTZAL() { RepZBranchLinki32(<) } // Branch if Rs < 0 and link
565
566/*********************************************************
567* Shift arithmetic with constant shift *
568* Format: OP rd, rt, sa *
569*********************************************************/
570void psxSLL() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) << _Sa_; } // Rd = Rt << sa
571void psxSRA() { if (!_Rd_) return; _i32(_rRd_) = _i32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (arithmetic)
572void psxSRL() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (logical)
573
574/*********************************************************
575* Shift arithmetic with variant register shift *
576* Format: OP rd, rt, rs *
577*********************************************************/
578void psxSLLV() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) << _u32(_rRs_); } // Rd = Rt << rs
579void psxSRAV() { if (!_Rd_) return; _i32(_rRd_) = _i32(_rRt_) >> _u32(_rRs_); } // Rd = Rt >> rs (arithmetic)
580void psxSRLV() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) >> _u32(_rRs_); } // Rd = Rt >> rs (logical)
581
582/*********************************************************
583* Load higher 16 bits of the first word in GPR with imm *
584* Format: OP rt, immediate *
585*********************************************************/
586void psxLUI() { if (!_Rt_) return; _u32(_rRt_) = psxRegs.code << 16; } // Upper halfword of Rt = Im
587
588/*********************************************************
589* Move from HI/LO to GPR *
590* Format: OP rd *
591*********************************************************/
592void psxMFHI() { if (!_Rd_) return; _rRd_ = _rHi_; } // Rd = Hi
593void psxMFLO() { if (!_Rd_) return; _rRd_ = _rLo_; } // Rd = Lo
594
595/*********************************************************
596* Move to GPR to HI/LO & Register jump *
597* Format: OP rs *
598*********************************************************/
599void psxMTHI() { _rHi_ = _rRs_; } // Hi = Rs
600void psxMTLO() { _rLo_ = _rRs_; } // Lo = Rs
601
602/*********************************************************
603* Special purpose instructions *
604* Format: OP *
605*********************************************************/
606void psxBREAK() {
607 // Break exception - psx rom doens't handles this
608}
609
610void psxSYSCALL() {
611 psxRegs.pc -= 4;
612 psxException(0x20, branch);
613}
614
615void psxRFE() {
616// SysPrintf("psxRFE\n");
617 psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status & 0xfffffff0) |
618 ((psxRegs.CP0.n.Status & 0x3c) >> 2);
619}
620
621/*********************************************************
622* Register branch logic *
623* Format: OP rs, rt, offset *
624*********************************************************/
625#define RepBranchi32(op) if(_i32(_rRs_) op _i32(_rRt_)) doBranch(_BranchTarget_);
626
627void psxBEQ() { RepBranchi32(==) } // Branch if Rs == Rt
628void psxBNE() { RepBranchi32(!=) } // Branch if Rs != Rt
629
630/*********************************************************
631* Jump to target *
632* Format: OP target *
633*********************************************************/
634void psxJ() { doBranch(_JumpTarget_); }
635void psxJAL() { _SetLink(31); doBranch(_JumpTarget_); }
636
637/*********************************************************
638* Register jump *
639* Format: OP rs, rd *
640*********************************************************/
641void psxJR() {
642 doBranch(_u32(_rRs_));
643 psxJumpTest();
644}
645
646void psxJALR() {
647 u32 temp = _u32(_rRs_);
648 if (_Rd_) { _SetLink(_Rd_); }
649 doBranch(temp);
650}
651
652/*********************************************************
653* Load and store for GPR *
654* Format: OP rt, offset(base) *
655*********************************************************/
656
657#define _oB_ (_u32(_rRs_) + _Imm_)
658
659void psxLB() {
660 if (_Rt_) {
661 _i32(_rRt_) = (signed char)psxMemRead8(_oB_);
662 } else {
663 psxMemRead8(_oB_);
664 }
665}
666
667void psxLBU() {
668 if (_Rt_) {
669 _u32(_rRt_) = psxMemRead8(_oB_);
670 } else {
671 psxMemRead8(_oB_);
672 }
673}
674
675void psxLH() {
676 if (_Rt_) {
677 _i32(_rRt_) = (short)psxMemRead16(_oB_);
678 } else {
679 psxMemRead16(_oB_);
680 }
681}
682
683void psxLHU() {
684 if (_Rt_) {
685 _u32(_rRt_) = psxMemRead16(_oB_);
686 } else {
687 psxMemRead16(_oB_);
688 }
689}
690
691void psxLW() {
692 if (_Rt_) {
693 _u32(_rRt_) = psxMemRead32(_oB_);
694 } else {
695 psxMemRead32(_oB_);
696 }
697}
698
699u32 LWL_MASK[4] = { 0xffffff, 0xffff, 0xff, 0 };
700u32 LWL_SHIFT[4] = { 24, 16, 8, 0 };
701
702void psxLWL() {
703 u32 addr = _oB_;
704 u32 shift = addr & 3;
705 u32 mem = psxMemRead32(addr & ~3);
706
707 if (!_Rt_) return;
708 _u32(_rRt_) = ( _u32(_rRt_) & LWL_MASK[shift]) |
709 ( mem << LWL_SHIFT[shift]);
710
711 /*
712 Mem = 1234. Reg = abcd
713
714 0 4bcd (mem << 24) | (reg & 0x00ffffff)
715 1 34cd (mem << 16) | (reg & 0x0000ffff)
716 2 234d (mem << 8) | (reg & 0x000000ff)
717 3 1234 (mem ) | (reg & 0x00000000)
718 */
719}
720
721u32 LWR_MASK[4] = { 0, 0xff000000, 0xffff0000, 0xffffff00 };
722u32 LWR_SHIFT[4] = { 0, 8, 16, 24 };
723
724void psxLWR() {
725 u32 addr = _oB_;
726 u32 shift = addr & 3;
727 u32 mem = psxMemRead32(addr & ~3);
728
729 if (!_Rt_) return;
730 _u32(_rRt_) = ( _u32(_rRt_) & LWR_MASK[shift]) |
731 ( mem >> LWR_SHIFT[shift]);
732
733 /*
734 Mem = 1234. Reg = abcd
735
736 0 1234 (mem ) | (reg & 0x00000000)
737 1 a123 (mem >> 8) | (reg & 0xff000000)
738 2 ab12 (mem >> 16) | (reg & 0xffff0000)
739 3 abc1 (mem >> 24) | (reg & 0xffffff00)
740 */
741}
742
b1ba0851 743void psxSB() { psxMemWrite8 (_oB_, _rRt_ & 0xff); }
744void psxSH() { psxMemWrite16(_oB_, _rRt_ & 0xffff); }
745void psxSW() { psxMemWrite32(_oB_, _rRt_); }
ef79bbde
P
746
747u32 SWL_MASK[4] = { 0xffffff00, 0xffff0000, 0xff000000, 0 };
748u32 SWL_SHIFT[4] = { 24, 16, 8, 0 };
749
750void psxSWL() {
751 u32 addr = _oB_;
752 u32 shift = addr & 3;
753 u32 mem = psxMemRead32(addr & ~3);
754
755 psxMemWrite32(addr & ~3, (_u32(_rRt_) >> SWL_SHIFT[shift]) |
756 ( mem & SWL_MASK[shift]) );
757 /*
758 Mem = 1234. Reg = abcd
759
760 0 123a (reg >> 24) | (mem & 0xffffff00)
761 1 12ab (reg >> 16) | (mem & 0xffff0000)
762 2 1abc (reg >> 8) | (mem & 0xff000000)
763 3 abcd (reg ) | (mem & 0x00000000)
764 */
765}
766
767u32 SWR_MASK[4] = { 0, 0xff, 0xffff, 0xffffff };
768u32 SWR_SHIFT[4] = { 0, 8, 16, 24 };
769
770void psxSWR() {
771 u32 addr = _oB_;
772 u32 shift = addr & 3;
773 u32 mem = psxMemRead32(addr & ~3);
774
775 psxMemWrite32(addr & ~3, (_u32(_rRt_) << SWR_SHIFT[shift]) |
776 ( mem & SWR_MASK[shift]) );
777
778 /*
779 Mem = 1234. Reg = abcd
780
781 0 abcd (reg ) | (mem & 0x00000000)
782 1 bcd4 (reg << 8) | (mem & 0x000000ff)
783 2 cd34 (reg << 16) | (mem & 0x0000ffff)
784 3 d234 (reg << 24) | (mem & 0x00ffffff)
785 */
786}
787
788/*********************************************************
789* Moves between GPR and COPx *
790* Format: OP rt, fs *
791*********************************************************/
792void psxMFC0() { if (!_Rt_) return; _i32(_rRt_) = (int)_rFs_; }
793void psxCFC0() { if (!_Rt_) return; _i32(_rRt_) = (int)_rFs_; }
794
795void psxTestSWInts() {
ef79bbde 796 if (psxRegs.CP0.n.Cause & psxRegs.CP0.n.Status & 0x0300 &&
48e74ef5 797 psxRegs.CP0.n.Status & 0x1) {
798 psxRegs.CP0.n.Cause &= ~0x7c;
ef79bbde
P
799 psxException(psxRegs.CP0.n.Cause, branch);
800 }
801}
802
4600ba03 803void MTC0(int reg, u32 val) {
ef79bbde
P
804// SysPrintf("MTC0 %d: %x\n", reg, val);
805 switch (reg) {
806 case 12: // Status
807 psxRegs.CP0.r[12] = val;
808 psxTestSWInts();
809 break;
810
811 case 13: // Cause
48e74ef5 812 psxRegs.CP0.n.Cause &= ~0x0300;
813 psxRegs.CP0.n.Cause |= val & 0x0300;
ef79bbde
P
814 psxTestSWInts();
815 break;
816
817 default:
818 psxRegs.CP0.r[reg] = val;
819 break;
820 }
821}
822
823void psxMTC0() { MTC0(_Rd_, _u32(_rRt_)); }
824void psxCTC0() { MTC0(_Rd_, _u32(_rRt_)); }
825
826/*********************************************************
827* Unknow instruction (would generate an exception) *
828* Format: ? *
829*********************************************************/
830void psxNULL() {
831#ifdef PSXCPU_LOG
832 PSXCPU_LOG("psx: Unimplemented op %x\n", psxRegs.code);
833#endif
834}
835
836void psxSPECIAL() {
837 psxSPC[_Funct_]();
838}
839
840void psxREGIMM() {
841 psxREG[_Rt_]();
842}
843
844void psxCOP0() {
845 psxCP0[_Rs_]();
846}
847
848void psxCOP2() {
6c0eefaf 849 psxCP2[_Funct_]((struct psxCP2Regs *)&psxRegs.CP2D);
ef79bbde
P
850}
851
6c0eefaf 852void psxBASIC(struct psxCP2Regs *regs) {
ef79bbde
P
853 psxCP2BSC[_Rs_]();
854}
855
856void psxHLE() {
857// psxHLEt[psxRegs.code & 0xffff]();
dd79da89 858// psxHLEt[psxRegs.code & 0x07](); // HDHOSHY experimental patch
859 uint32_t hleCode = psxRegs.code & 0x03ffffff;
860 if (hleCode >= (sizeof(psxHLEt) / sizeof(psxHLEt[0]))) {
861 psxNULL();
862 } else {
863 psxHLEt[hleCode]();
864 }
ef79bbde
P
865}
866
867void (*psxBSC[64])() = {
868 psxSPECIAL, psxREGIMM, psxJ , psxJAL , psxBEQ , psxBNE , psxBLEZ, psxBGTZ,
869 psxADDI , psxADDIU , psxSLTI, psxSLTIU, psxANDI, psxORI , psxXORI, psxLUI ,
870 psxCOP0 , psxNULL , psxCOP2, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL,
871 psxNULL , psxNULL , psxNULL, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL,
872 psxLB , psxLH , psxLWL , psxLW , psxLBU , psxLHU , psxLWR , psxNULL,
873 psxSB , psxSH , psxSWL , psxSW , psxNULL, psxNULL, psxSWR , psxNULL,
874 psxNULL , psxNULL , gteLWC2, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL,
875 psxNULL , psxNULL , gteSWC2, psxHLE , psxNULL, psxNULL, psxNULL, psxNULL
876};
877
878
879void (*psxSPC[64])() = {
880 psxSLL , psxNULL , psxSRL , psxSRA , psxSLLV , psxNULL , psxSRLV, psxSRAV,
881 psxJR , psxJALR , psxNULL, psxNULL, psxSYSCALL, psxBREAK, psxNULL, psxNULL,
882 psxMFHI, psxMTHI , psxMFLO, psxMTLO, psxNULL , psxNULL , psxNULL, psxNULL,
883 psxMULT, psxMULTU, psxDIV , psxDIVU, psxNULL , psxNULL , psxNULL, psxNULL,
884 psxADD , psxADDU , psxSUB , psxSUBU, psxAND , psxOR , psxXOR , psxNOR ,
885 psxNULL, psxNULL , psxSLT , psxSLTU, psxNULL , psxNULL , psxNULL, psxNULL,
886 psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL,
887 psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL
888};
889
890void (*psxREG[32])() = {
891 psxBLTZ , psxBGEZ , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
892 psxNULL , psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
893 psxBLTZAL, psxBGEZAL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
894 psxNULL , psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL
895};
896
897void (*psxCP0[32])() = {
898 psxMFC0, psxNULL, psxCFC0, psxNULL, psxMTC0, psxNULL, psxCTC0, psxNULL,
899 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
900 psxRFE , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
901 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL
902};
903
6c0eefaf 904void (*psxCP2[64])(struct psxCP2Regs *regs) = {
ef79bbde
P
905 psxBASIC, gteRTPS , psxNULL , psxNULL, psxNULL, psxNULL , gteNCLIP, psxNULL, // 00
906 psxNULL , psxNULL , psxNULL , psxNULL, gteOP , psxNULL , psxNULL , psxNULL, // 08
907 gteDPCS , gteINTPL, gteMVMVA, gteNCDS, gteCDP , psxNULL , gteNCDT , psxNULL, // 10
908 psxNULL , psxNULL , psxNULL , gteNCCS, gteCC , psxNULL , gteNCS , psxNULL, // 18
909 gteNCT , psxNULL , psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, // 20
910 gteSQR , gteDCPL , gteDPCT , psxNULL, psxNULL, gteAVSZ3, gteAVSZ4, psxNULL, // 28
911 gteRTPT , psxNULL , psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, // 30
912 psxNULL , psxNULL , psxNULL , psxNULL, psxNULL, gteGPF , gteGPL , gteNCCT // 38
913};
914
915void (*psxCP2BSC[32])() = {
916 gteMFC2, psxNULL, gteCFC2, psxNULL, gteMTC2, psxNULL, gteCTC2, psxNULL,
917 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
918 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
919 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL
920};
921
922
923///////////////////////////////////////////
924
925static int intInit() {
926 return 0;
927}
928
929static void intReset() {
930}
931
796a91ef 932void intExecute() {
933 extern int stop;
934 for (;!stop;)
ef79bbde
P
935 execI();
936}
937
796a91ef 938void intExecuteBlock() {
ef79bbde
P
939 branch2 = 0;
940 while (!branch2) execI();
941}
942
943static void intClear(u32 Addr, u32 Size) {
944}
945
946static void intShutdown() {
947}
948
949// interpreter execution
4600ba03 950void execI() {
ef79bbde
P
951 u32 *code = (u32 *)PSXM(psxRegs.pc);
952 psxRegs.code = ((code == NULL) ? 0 : SWAP32(*code));
953
954 debugI();
955
956 if (Config.Debug) ProcessDebug();
957
958 psxRegs.pc += 4;
959 psxRegs.cycle += BIAS;
960
961 psxBSC[psxRegs.code >> 26]();
962}
963
964R3000Acpu psxInt = {
965 intInit,
966 intReset,
967 intExecute,
968 intExecuteBlock,
969 intClear,
970 intShutdown
971};