1 /***************************************************************************
2 * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team *
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. *
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. *
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 ***************************************************************************/
21 * PSX assembly interpreter.
24 #include "psxcommon.h"
29 #include "psxinterpreter.h"
32 static int branch = 0;
33 static int branch2 = 0;
36 // These macros are used to assemble the repassembler functions
39 #define debugI() PSXCPU_LOG("%s\n", disR3000AF(psxRegs.code, psxRegs.pc));
49 void (*psxCP2[64])(struct psxCP2Regs *regs);
50 void (*psxCP2BSC[32])();
52 static u32 fetchNoCache(u32 pc)
54 u32 *code = (u32 *)PSXM(pc);
55 return ((code == NULL) ? 0 : SWAP32(*code));
60 Use old CPU cache code when the RAM location is updated with new code (affects in-game racing)
62 static struct cache_entry {
67 static u32 fetchICache(u32 pc)
72 // this is not how the hardware works but whatever
73 struct cache_entry *entry = &ICache[(pc & 0xff0) >> 4];
75 if (((entry->tag ^ pc) & 0xfffffff0) != 0 || pc < entry->tag)
77 u32 *code = (u32 *)PSXM(pc & ~0x0f);
82 // treat as 4 words, although other configurations are said to be possible
85 case 0x00: entry->data[0] = SWAP32(code[0]);
86 case 0x04: entry->data[1] = SWAP32(code[1]);
87 case 0x08: entry->data[2] = SWAP32(code[2]);
88 case 0x0c: entry->data[3] = SWAP32(code[3]);
91 return entry->data[(pc & 0x0f) >> 2];
94 return fetchNoCache(pc);
97 u32 (*fetch)(u32 pc) = fetchNoCache;
99 static void delayRead(int reg, u32 bpc) {
102 // SysPrintf("delayRead at %x!\n", psxRegs.pc);
104 rold = psxRegs.GPR.r[reg];
105 psxBSC[psxRegs.code >> 26](); // branch delay load
106 rnew = psxRegs.GPR.r[reg];
112 psxRegs.GPR.r[reg] = rold;
113 execI(); // first branch opcode
114 psxRegs.GPR.r[reg] = rnew;
119 static void delayWrite(int reg, u32 bpc) {
121 /* SysPrintf("delayWrite at %x!\n", psxRegs.pc);
123 SysPrintf("%s\n", disR3000AF(psxRegs.code, psxRegs.pc-4));
124 SysPrintf("%s\n", disR3000AF(PSXMu32(bpc), bpc));*/
126 // no changes from normal behavior
128 psxBSC[psxRegs.code >> 26]();
136 static void delayReadWrite(int reg, u32 bpc) {
138 // SysPrintf("delayReadWrite at %x!\n", psxRegs.pc);
140 // the branch delay load is skipped
148 // this defines shall be used with the tmp
149 // of the next func (instead of _Funct_...)
150 #define _tFunct_ ((tmp ) & 0x3F) // The funct part of the instruction register
151 #define _tRd_ ((tmp >> 11) & 0x1F) // The rd part of the instruction register
152 #define _tRt_ ((tmp >> 16) & 0x1F) // The rt part of the instruction register
153 #define _tRs_ ((tmp >> 21) & 0x1F) // The rs part of the instruction register
154 #define _tSa_ ((tmp >> 6) & 0x1F) // The sa part of the instruction register
156 int psxTestLoadDelay(int reg, u32 tmp) {
157 if (tmp == 0) return 0; // NOP
159 case 0x00: // SPECIAL
162 case 0x02: case 0x03: // SRL/SRA
163 if (_tRd_ == reg && _tRt_ == reg) return 1; else
164 if (_tRt_ == reg) return 2; else
165 if (_tRd_ == reg) return 3;
169 if (_tRs_ == reg) return 2;
172 if (_tRd_ == reg && _tRs_ == reg) return 1; else
173 if (_tRs_ == reg) return 2; else
174 if (_tRd_ == reg) return 3;
177 // SYSCALL/BREAK just a break;
179 case 0x20: case 0x21: case 0x22: case 0x23:
180 case 0x24: case 0x25: case 0x26: case 0x27:
181 case 0x2a: case 0x2b: // ADD/ADDU...
182 case 0x04: case 0x06: case 0x07: // SLLV...
183 if (_tRd_ == reg && (_tRt_ == reg || _tRs_ == reg)) return 1; else
184 if (_tRt_ == reg || _tRs_ == reg) return 2; else
185 if (_tRd_ == reg) return 3;
188 case 0x10: case 0x12: // MFHI/MFLO
189 if (_tRd_ == reg) return 3;
191 case 0x11: case 0x13: // MTHI/MTLO
192 if (_tRs_ == reg) return 2;
195 case 0x18: case 0x19:
196 case 0x1a: case 0x1b: // MULT/DIV...
197 if (_tRt_ == reg || _tRs_ == reg) return 2;
204 case 0x00: case 0x01:
205 case 0x10: case 0x11: // BLTZ/BGEZ...
206 // Xenogears - lbu v0 / beq v0
207 // - no load delay (fixes battle loading)
210 if (_tRs_ == reg) return 2;
215 // J would be just a break;
217 if (31 == reg) return 3;
220 case 0x04: case 0x05: // BEQ/BNE
221 // Xenogears - lbu v0 / beq v0
222 // - no load delay (fixes battle loading)
225 if (_tRs_ == reg || _tRt_ == reg) return 2;
228 case 0x06: case 0x07: // BLEZ/BGTZ
229 // Xenogears - lbu v0 / beq v0
230 // - no load delay (fixes battle loading)
233 if (_tRs_ == reg) return 2;
236 case 0x08: case 0x09: case 0x0a: case 0x0b:
237 case 0x0c: case 0x0d: case 0x0e: // ADDI/ADDIU...
238 if (_tRt_ == reg && _tRs_ == reg) return 1; else
239 if (_tRs_ == reg) return 2; else
240 if (_tRt_ == reg) return 3;
244 if (_tRt_ == reg) return 3;
250 if (_tRt_ == reg) return 3;
253 if (_tRt_ == reg) return 3;
256 if (_tRt_ == reg) return 2;
259 if (_tRt_ == reg) return 2;
270 if (_tRt_ == reg) return 3;
273 if (_tRt_ == reg) return 3;
276 if (_tRt_ == reg) return 2;
279 if (_tRt_ == reg) return 2;
287 case 0x22: case 0x26: // LWL/LWR
288 if (_tRt_ == reg) return 3; else
289 if (_tRs_ == reg) return 2;
292 case 0x20: case 0x21: case 0x23:
293 case 0x24: case 0x25: // LB/LH/LW/LBU/LHU
294 if (_tRt_ == reg && _tRs_ == reg) return 1; else
295 if (_tRs_ == reg) return 2; else
296 if (_tRt_ == reg) return 3;
299 case 0x28: case 0x29: case 0x2a:
300 case 0x2b: case 0x2e: // SB/SH/SWL/SW/SWR
301 if (_tRt_ == reg || _tRs_ == reg) return 2;
304 case 0x32: case 0x3a: // LWC2/SWC2
305 if (_tRs_ == reg) return 2;
312 void psxDelayTest(int reg, u32 bpc) {
313 u32 tmp = fetch(psxRegs.pc);
316 switch (psxTestLoadDelay(reg, tmp)) {
318 delayReadWrite(reg, bpc); return;
320 delayRead(reg, bpc); return;
322 delayWrite(reg, bpc); return;
324 psxBSC[psxRegs.code >> 26]();
332 static u32 psxBranchNoDelay(void) {
335 psxRegs.code = fetch(psxRegs.pc);
337 case 0x00: // SPECIAL
343 if (_Rd_) { _SetLink(_Rd_); }
351 return _BranchTarget_;
354 if (_i32(_rRs_) >= 0)
355 return _BranchTarget_;
358 if (_i32(_rRs_) < 0) {
360 return _BranchTarget_;
364 if (_i32(_rRs_) >= 0) {
366 return _BranchTarget_;
377 if (_i32(_rRs_) == _i32(_rRt_))
378 return _BranchTarget_;
381 if (_i32(_rRs_) != _i32(_rRt_))
382 return _BranchTarget_;
385 if (_i32(_rRs_) <= 0)
386 return _BranchTarget_;
390 return _BranchTarget_;
397 static int psxDelayBranchExec(u32 tar) {
402 psxRegs.cycle += BIAS;
407 static int psxDelayBranchTest(u32 tar1) {
408 u32 tar2, tmp1, tmp2;
410 tar2 = psxBranchNoDelay();
417 * Branch in delay slot:
418 * - execute 1 instruction at tar1
419 * - jump to tar2 (target of branch in delay slot; this branch
420 * has no normal delay slot, instruction at tar1 was fetched instead)
423 tmp1 = psxBranchNoDelay();
424 if (tmp1 == (u32)-1) {
425 return psxDelayBranchExec(tar2);
428 psxRegs.cycle += BIAS;
431 * Got a branch at tar1:
432 * - execute 1 instruction at tar2
433 * - jump to target of that branch (tmp1)
436 tmp2 = psxBranchNoDelay();
437 if (tmp2 == (u32)-1) {
438 return psxDelayBranchExec(tmp1);
441 psxRegs.cycle += BIAS;
444 * Got a branch at tar2:
445 * - execute 1 instruction at tmp1
446 * - jump to target of that branch (tmp2)
449 return psxDelayBranchExec(tmp2);
452 static void doBranch(u32 tar) {
455 branch2 = branch = 1;
458 // check for branch in delay slot
459 if (psxDelayBranchTest(tar))
462 psxRegs.code = fetch(psxRegs.pc);
467 psxRegs.cycle += BIAS;
469 // check for load delay
470 tmp = psxRegs.code >> 26;
476 psxDelayTest(_Rt_, branchPC);
486 psxDelayTest(_Rt_, branchPC);
493 psxDelayTest(_Rt_, branchPC);
496 if (tmp >= 0x20 && tmp <= 0x26) { // LB/LH/LWL/LW/LBU/LHU/LWR
497 psxDelayTest(_Rt_, branchPC);
503 psxBSC[psxRegs.code >> 26]();
506 psxRegs.pc = branchPC;
511 /*********************************************************
512 * Arithmetic with immediate operand *
513 * Format: OP rt, rs, immediate *
514 *********************************************************/
515 void psxADDI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im (Exception on Integer Overflow)
516 void psxADDIU() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im
517 void psxANDI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) & _ImmU_; } // Rt = Rs And Im
518 void psxORI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) | _ImmU_; } // Rt = Rs Or Im
519 void psxXORI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) ^ _ImmU_; } // Rt = Rs Xor Im
520 void psxSLTI() { if (!_Rt_) return; _rRt_ = _i32(_rRs_) < _Imm_ ; } // Rt = Rs < Im (Signed)
521 void psxSLTIU() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) < ((u32)_Imm_); } // Rt = Rs < Im (Unsigned)
523 /*********************************************************
524 * Register arithmetic *
525 * Format: OP rd, rs, rt *
526 *********************************************************/
527 void psxADD() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt (Exception on Integer Overflow)
528 void psxADDU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt
529 void psxSUB() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt (Exception on Integer Overflow)
530 void psxSUBU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt
531 void psxAND() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) & _u32(_rRt_); } // Rd = Rs And Rt
532 void psxOR() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) | _u32(_rRt_); } // Rd = Rs Or Rt
533 void psxXOR() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) ^ _u32(_rRt_); } // Rd = Rs Xor Rt
534 void psxNOR() { if (!_Rd_) return; _rRd_ =~(_u32(_rRs_) | _u32(_rRt_)); }// Rd = Rs Nor Rt
535 void psxSLT() { if (!_Rd_) return; _rRd_ = _i32(_rRs_) < _i32(_rRt_); } // Rd = Rs < Rt (Signed)
536 void psxSLTU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) < _u32(_rRt_); } // Rd = Rs < Rt (Unsigned)
538 /*********************************************************
539 * Register mult/div & Register trap logic *
540 * Format: OP rs, rt *
541 *********************************************************/
544 _i32(_rHi_) = _i32(_rRs_);
545 if (_i32(_rRs_) & 0x80000000) {
548 _i32(_rLo_) = 0xFFFFFFFF;
551 * Notaz said that this was "not needed" for ARM platforms and could slow it down so let's disable for ARM.
552 * This fixes a crash issue that can happen when running Amidog's CPU test.
553 * (It still stays stuck to a black screen but at least it doesn't crash anymore)
555 #if !defined(__arm__) && !defined(__aarch64__)
556 } else if (_i32(_rRs_) == 0x80000000 && _i32(_rRt_) == 0xFFFFFFFF) {
557 _i32(_rLo_) = 0x80000000;
561 _i32(_rLo_) = _i32(_rRs_) / _i32(_rRt_);
562 _i32(_rHi_) = _i32(_rRs_) % _i32(_rRt_);
566 void psxDIV_stall() {
567 psxRegs.muldivBusyCycle = psxRegs.cycle + 37;
573 _rLo_ = _rRs_ / _rRt_;
574 _rHi_ = _rRs_ % _rRt_;
577 _i32(_rLo_) = 0xffffffff;
578 _i32(_rHi_) = _i32(_rRs_);
582 void psxDIVU_stall() {
583 psxRegs.muldivBusyCycle = psxRegs.cycle + 37;
588 u64 res = (s64)((s64)_i32(_rRs_) * (s64)_i32(_rRt_));
590 psxRegs.GPR.n.lo = (u32)(res & 0xffffffff);
591 psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff);
594 void psxMULT_stall() {
595 // approximate, but maybe good enough
597 u32 lz = __builtin_clz(((rs ^ ((s32)rs >> 21)) | 1));
598 u32 c = 7 + (2 - (lz / 11)) * 4;
599 psxRegs.muldivBusyCycle = psxRegs.cycle + c;
604 u64 res = (u64)((u64)_u32(_rRs_) * (u64)_u32(_rRt_));
606 psxRegs.GPR.n.lo = (u32)(res & 0xffffffff);
607 psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff);
610 void psxMULTU_stall() {
611 // approximate, but maybe good enough
612 u32 lz = __builtin_clz(_rRs_ | 1);
613 u32 c = 7 + (2 - (lz / 11)) * 4;
614 psxRegs.muldivBusyCycle = psxRegs.cycle + c;
618 /*********************************************************
619 * Register branch logic *
620 * Format: OP rs, offset *
621 *********************************************************/
622 #define RepZBranchi32(op) if(_i32(_rRs_) op 0) doBranch(_BranchTarget_);
623 #define RepZBranchLinki32(op) { _SetLink(31); if(_i32(_rRs_) op 0) { doBranch(_BranchTarget_); } }
625 void psxBGEZ() { RepZBranchi32(>=) } // Branch if Rs >= 0
626 void psxBGEZAL() { RepZBranchLinki32(>=) } // Branch if Rs >= 0 and link
627 void psxBGTZ() { RepZBranchi32(>) } // Branch if Rs > 0
628 void psxBLEZ() { RepZBranchi32(<=) } // Branch if Rs <= 0
629 void psxBLTZ() { RepZBranchi32(<) } // Branch if Rs < 0
630 void psxBLTZAL() { RepZBranchLinki32(<) } // Branch if Rs < 0 and link
632 /*********************************************************
633 * Shift arithmetic with constant shift *
634 * Format: OP rd, rt, sa *
635 *********************************************************/
636 void psxSLL() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) << _Sa_; } // Rd = Rt << sa
637 void psxSRA() { if (!_Rd_) return; _i32(_rRd_) = _i32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (arithmetic)
638 void psxSRL() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (logical)
640 /*********************************************************
641 * Shift arithmetic with variant register shift *
642 * Format: OP rd, rt, rs *
643 *********************************************************/
644 void psxSLLV() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) << (_u32(_rRs_) & 0x1F); } // Rd = Rt << rs
645 void psxSRAV() { if (!_Rd_) return; _i32(_rRd_) = _i32(_rRt_) >> (_u32(_rRs_) & 0x1F); } // Rd = Rt >> rs (arithmetic)
646 void psxSRLV() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) >> (_u32(_rRs_) & 0x1F); } // Rd = Rt >> rs (logical)
648 /*********************************************************
649 * Load higher 16 bits of the first word in GPR with imm *
650 * Format: OP rt, immediate *
651 *********************************************************/
652 void psxLUI() { if (!_Rt_) return; _u32(_rRt_) = psxRegs.code << 16; } // Upper halfword of Rt = Im
654 /*********************************************************
655 * Move from HI/LO to GPR *
657 *********************************************************/
658 void psxMFHI() { if (!_Rd_) return; _rRd_ = _rHi_; } // Rd = Hi
659 void psxMFLO() { if (!_Rd_) return; _rRd_ = _rLo_; } // Rd = Lo
661 static void mflohiCheckStall(void)
663 u32 left = psxRegs.muldivBusyCycle - psxRegs.cycle;
665 //printf("muldiv stall %u\n", left);
666 psxRegs.cycle = psxRegs.muldivBusyCycle;
670 void psxMFHI_stall() { mflohiCheckStall(); psxMFHI(); }
671 void psxMFLO_stall() { mflohiCheckStall(); psxMFLO(); }
673 /*********************************************************
674 * Move to GPR to HI/LO & Register jump *
676 *********************************************************/
677 void psxMTHI() { _rHi_ = _rRs_; } // Hi = Rs
678 void psxMTLO() { _rLo_ = _rRs_; } // Lo = Rs
680 /*********************************************************
681 * Special purpose instructions *
683 *********************************************************/
686 psxException(0x24, branch);
691 psxException(0x20, branch);
695 // SysPrintf("psxRFE\n");
696 psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status & 0xfffffff0) |
697 ((psxRegs.CP0.n.Status & 0x3c) >> 2);
701 /*********************************************************
702 * Register branch logic *
703 * Format: OP rs, rt, offset *
704 *********************************************************/
705 #define RepBranchi32(op) if(_i32(_rRs_) op _i32(_rRt_)) doBranch(_BranchTarget_);
707 void psxBEQ() { RepBranchi32(==) } // Branch if Rs == Rt
708 void psxBNE() { RepBranchi32(!=) } // Branch if Rs != Rt
710 /*********************************************************
712 * Format: OP target *
713 *********************************************************/
714 void psxJ() { doBranch(_JumpTarget_); }
715 void psxJAL() { _SetLink(31); doBranch(_JumpTarget_); }
717 /*********************************************************
719 * Format: OP rs, rd *
720 *********************************************************/
722 doBranch(_rRs_ & ~3);
727 u32 temp = _u32(_rRs_);
728 if (_Rd_) { _SetLink(_Rd_); }
732 /*********************************************************
733 * Load and store for GPR *
734 * Format: OP rt, offset(base) *
735 *********************************************************/
737 #define _oB_ (_u32(_rRs_) + _Imm_)
741 _i32(_rRt_) = (signed char)psxMemRead8(_oB_);
749 _u32(_rRt_) = psxMemRead8(_oB_);
757 _i32(_rRt_) = (short)psxMemRead16(_oB_);
765 _u32(_rRt_) = psxMemRead16(_oB_);
773 _u32(_rRt_) = psxMemRead32(_oB_);
779 u32 LWL_MASK[4] = { 0xffffff, 0xffff, 0xff, 0 };
780 u32 LWL_SHIFT[4] = { 24, 16, 8, 0 };
784 u32 shift = addr & 3;
785 u32 mem = psxMemRead32(addr & ~3);
788 _u32(_rRt_) = ( _u32(_rRt_) & LWL_MASK[shift]) |
789 ( mem << LWL_SHIFT[shift]);
792 Mem = 1234. Reg = abcd
794 0 4bcd (mem << 24) | (reg & 0x00ffffff)
795 1 34cd (mem << 16) | (reg & 0x0000ffff)
796 2 234d (mem << 8) | (reg & 0x000000ff)
797 3 1234 (mem ) | (reg & 0x00000000)
801 u32 LWR_MASK[4] = { 0, 0xff000000, 0xffff0000, 0xffffff00 };
802 u32 LWR_SHIFT[4] = { 0, 8, 16, 24 };
806 u32 shift = addr & 3;
807 u32 mem = psxMemRead32(addr & ~3);
810 _u32(_rRt_) = ( _u32(_rRt_) & LWR_MASK[shift]) |
811 ( mem >> LWR_SHIFT[shift]);
814 Mem = 1234. Reg = abcd
816 0 1234 (mem ) | (reg & 0x00000000)
817 1 a123 (mem >> 8) | (reg & 0xff000000)
818 2 ab12 (mem >> 16) | (reg & 0xffff0000)
819 3 abc1 (mem >> 24) | (reg & 0xffffff00)
823 void psxSB() { psxMemWrite8 (_oB_, _rRt_ & 0xff); }
824 void psxSH() { psxMemWrite16(_oB_, _rRt_ & 0xffff); }
825 void psxSW() { psxMemWrite32(_oB_, _rRt_); }
827 u32 SWL_MASK[4] = { 0xffffff00, 0xffff0000, 0xff000000, 0 };
828 u32 SWL_SHIFT[4] = { 24, 16, 8, 0 };
832 u32 shift = addr & 3;
833 u32 mem = psxMemRead32(addr & ~3);
835 psxMemWrite32(addr & ~3, (_u32(_rRt_) >> SWL_SHIFT[shift]) |
836 ( mem & SWL_MASK[shift]) );
838 Mem = 1234. Reg = abcd
840 0 123a (reg >> 24) | (mem & 0xffffff00)
841 1 12ab (reg >> 16) | (mem & 0xffff0000)
842 2 1abc (reg >> 8) | (mem & 0xff000000)
843 3 abcd (reg ) | (mem & 0x00000000)
847 u32 SWR_MASK[4] = { 0, 0xff, 0xffff, 0xffffff };
848 u32 SWR_SHIFT[4] = { 0, 8, 16, 24 };
852 u32 shift = addr & 3;
853 u32 mem = psxMemRead32(addr & ~3);
855 psxMemWrite32(addr & ~3, (_u32(_rRt_) << SWR_SHIFT[shift]) |
856 ( mem & SWR_MASK[shift]) );
859 Mem = 1234. Reg = abcd
861 0 abcd (reg ) | (mem & 0x00000000)
862 1 bcd4 (reg << 8) | (mem & 0x000000ff)
863 2 cd34 (reg << 16) | (mem & 0x0000ffff)
864 3 d234 (reg << 24) | (mem & 0x00ffffff)
868 /*********************************************************
869 * Moves between GPR and COPx *
870 * Format: OP rt, fs *
871 *********************************************************/
872 void psxMFC0() { if (!_Rt_) return; _i32(_rRt_) = (int)_rFs_; }
873 void psxCFC0() { if (!_Rt_) return; _i32(_rRt_) = (int)_rFs_; }
875 void psxTestSWInts() {
876 if (psxRegs.CP0.n.Cause & psxRegs.CP0.n.Status & 0x0300 &&
877 psxRegs.CP0.n.Status & 0x1) {
878 psxRegs.CP0.n.Cause &= ~0x7c;
879 psxException(psxRegs.CP0.n.Cause, branch);
883 void MTC0(int reg, u32 val) {
884 // SysPrintf("MTC0 %d: %x\n", reg, val);
887 psxRegs.CP0.r[12] = val;
892 psxRegs.CP0.n.Cause &= ~0x0300;
893 psxRegs.CP0.n.Cause |= val & 0x0300;
898 psxRegs.CP0.r[reg] = val;
903 void psxMTC0() { MTC0(_Rd_, _u32(_rRt_)); }
904 void psxCTC0() { MTC0(_Rd_, _u32(_rRt_)); }
906 /*********************************************************
907 * Unknow instruction (would generate an exception) *
909 *********************************************************/
912 PSXCPU_LOG("psx: Unimplemented op %x\n", psxRegs.code);
929 psxCP2[_Funct_]((struct psxCP2Regs *)&psxRegs.CP2D);
932 void psxCOP2_stall() {
935 psxCP2[f]((struct psxCP2Regs *)&psxRegs.CP2D);
938 void psxBASIC(struct psxCP2Regs *regs) {
943 // psxHLEt[psxRegs.code & 0xffff]();
944 // psxHLEt[psxRegs.code & 0x07](); // HDHOSHY experimental patch
945 uint32_t hleCode = psxRegs.code & 0x03ffffff;
946 if (hleCode >= (sizeof(psxHLEt) / sizeof(psxHLEt[0]))) {
953 void (*psxBSC[64])() = {
954 psxSPECIAL, psxREGIMM, psxJ , psxJAL , psxBEQ , psxBNE , psxBLEZ, psxBGTZ,
955 psxADDI , psxADDIU , psxSLTI, psxSLTIU, psxANDI, psxORI , psxXORI, psxLUI ,
956 psxCOP0 , psxNULL , psxCOP2, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL,
957 psxNULL , psxNULL , psxNULL, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL,
958 psxLB , psxLH , psxLWL , psxLW , psxLBU , psxLHU , psxLWR , psxNULL,
959 psxSB , psxSH , psxSWL , psxSW , psxNULL, psxNULL, psxSWR , psxNULL,
960 psxNULL , psxNULL , gteLWC2, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL,
961 psxNULL , psxNULL , gteSWC2, psxHLE , psxNULL, psxNULL, psxNULL, psxNULL
965 void (*psxSPC[64])() = {
966 psxSLL , psxNULL , psxSRL , psxSRA , psxSLLV , psxNULL , psxSRLV, psxSRAV,
967 psxJR , psxJALR , psxNULL, psxNULL, psxSYSCALL, psxBREAK, psxNULL, psxNULL,
968 psxMFHI, psxMTHI , psxMFLO, psxMTLO, psxNULL , psxNULL , psxNULL, psxNULL,
969 psxMULT, psxMULTU, psxDIV , psxDIVU, psxNULL , psxNULL , psxNULL, psxNULL,
970 psxADD , psxADDU , psxSUB , psxSUBU, psxAND , psxOR , psxXOR , psxNOR ,
971 psxNULL, psxNULL , psxSLT , psxSLTU, psxNULL , psxNULL , psxNULL, psxNULL,
972 psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL,
973 psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL
976 void (*psxREG[32])() = {
977 psxBLTZ , psxBGEZ , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
978 psxNULL , psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
979 psxBLTZAL, psxBGEZAL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
980 psxNULL , psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL
983 void (*psxCP0[32])() = {
984 psxMFC0, psxNULL, psxCFC0, psxNULL, psxMTC0, psxNULL, psxCTC0, psxNULL,
985 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
986 psxRFE , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
987 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL
990 void (*psxCP2[64])(struct psxCP2Regs *regs) = {
991 psxBASIC, gteRTPS , psxNULL , psxNULL, psxNULL, psxNULL , gteNCLIP, psxNULL, // 00
992 psxNULL , psxNULL , psxNULL , psxNULL, gteOP , psxNULL , psxNULL , psxNULL, // 08
993 gteDPCS , gteINTPL, gteMVMVA, gteNCDS, gteCDP , psxNULL , gteNCDT , psxNULL, // 10
994 psxNULL , psxNULL , psxNULL , gteNCCS, gteCC , psxNULL , gteNCS , psxNULL, // 18
995 gteNCT , psxNULL , psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, // 20
996 gteSQR , gteDCPL , gteDPCT , psxNULL, psxNULL, gteAVSZ3, gteAVSZ4, psxNULL, // 28
997 gteRTPT , psxNULL , psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, // 30
998 psxNULL , psxNULL , psxNULL , psxNULL, psxNULL, gteGPF , gteGPL , gteNCCT // 38
1001 void (*psxCP2BSC[32])() = {
1002 gteMFC2, psxNULL, gteCFC2, psxNULL, gteMTC2, psxNULL, gteCTC2, psxNULL,
1003 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
1004 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
1005 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL
1009 ///////////////////////////////////////////
1011 static int intInit() {
1015 static void intReset() {
1016 memset(&ICache, 0xff, sizeof(ICache));
1025 void intExecuteBlock() {
1027 while (!branch2) execI();
1030 static void intClear(u32 Addr, u32 Size) {
1033 void intNotify (int note, void *data) {
1034 /* Gameblabla - Only clear the icache if it's isolated */
1035 if (note == R3000ACPU_NOTIFY_CACHE_ISOLATED)
1037 memset(&ICache, 0xff, sizeof(ICache));
1041 void intApplyConfig() {
1042 assert(psxBSC[18] == psxCOP2 || psxBSC[18] == psxCOP2_stall);
1043 assert(psxBSC[50] == gteLWC2 || psxBSC[50] == gteLWC2_stall);
1044 assert(psxBSC[58] == gteSWC2 || psxBSC[58] == gteSWC2_stall);
1045 assert(psxSPC[16] == psxMFHI || psxSPC[16] == psxMFHI_stall);
1046 assert(psxSPC[18] == psxMFLO || psxSPC[18] == psxMFLO_stall);
1047 assert(psxSPC[24] == psxMULT || psxSPC[24] == psxMULT_stall);
1048 assert(psxSPC[25] == psxMULTU || psxSPC[25] == psxMULTU_stall);
1049 assert(psxSPC[26] == psxDIV || psxSPC[26] == psxDIV_stall);
1050 assert(psxSPC[27] == psxDIVU || psxSPC[27] == psxDIVU_stall);
1052 if (Config.DisableStalls) {
1053 psxBSC[18] = psxCOP2;
1054 psxBSC[50] = gteLWC2;
1055 psxBSC[58] = gteSWC2;
1056 psxSPC[16] = psxMFHI;
1057 psxSPC[18] = psxMFLO;
1058 psxSPC[24] = psxMULT;
1059 psxSPC[25] = psxMULTU;
1060 psxSPC[26] = psxDIV;
1061 psxSPC[27] = psxDIVU;
1063 psxBSC[18] = psxCOP2_stall;
1064 psxBSC[50] = gteLWC2_stall;
1065 psxBSC[58] = gteSWC2_stall;
1066 psxSPC[16] = psxMFHI_stall;
1067 psxSPC[18] = psxMFLO_stall;
1068 psxSPC[24] = psxMULT_stall;
1069 psxSPC[25] = psxMULTU_stall;
1070 psxSPC[26] = psxDIV_stall;
1071 psxSPC[27] = psxDIVU_stall;
1074 // dynarec may occasionally call the interpreter, in such a case the
1075 // cache won't work (cache only works right if all fetches go through it)
1076 if (!Config.icache_emulation || psxCpu != &psxInt)
1077 fetch = fetchNoCache;
1079 fetch = fetchICache;
1082 static void intShutdown() {
1085 // interpreter execution
1087 psxRegs.code = fetch(psxRegs.pc);
1091 if (Config.Debug) ProcessDebug();
1094 psxRegs.cycle += BIAS;
1096 psxBSC[psxRegs.code >> 26]();
1099 R3000Acpu psxInt = {