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