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"
28 #include "psxinterpreter.h"
31 #define ProcessDebug()
33 static int branch = 0;
34 static int branch2 = 0;
37 // These macros are used to assemble the repassembler functions
40 #define debugI() PSXCPU_LOG("%s\n", disR3000AF(psxRegs.code, psxRegs.pc));
50 void (*psxCP2[64])(struct psxCP2Regs *regs);
51 void (*psxCP2BSC[32])();
53 static u32 fetchNoCache(u32 pc)
55 u32 *code = (u32 *)PSXM(pc);
56 return ((code == NULL) ? 0 : SWAP32(*code));
61 Use old CPU cache code when the RAM location is updated with new code (affects in-game racing)
63 static struct cache_entry {
68 static u32 fetchICache(u32 pc)
73 // this is not how the hardware works but whatever
74 struct cache_entry *entry = &ICache[(pc & 0xff0) >> 4];
76 if (((entry->tag ^ pc) & 0xfffffff0) != 0 || pc < entry->tag)
78 u32 *code = (u32 *)PSXM(pc & ~0x0f);
83 // treat as 4 words, although other configurations are said to be possible
86 case 0x00: entry->data[0] = SWAP32(code[0]);
87 case 0x04: entry->data[1] = SWAP32(code[1]);
88 case 0x08: entry->data[2] = SWAP32(code[2]);
89 case 0x0c: entry->data[3] = SWAP32(code[3]);
92 return entry->data[(pc & 0x0f) >> 2];
95 return fetchNoCache(pc);
98 u32 (*fetch)(u32 pc) = fetchNoCache;
100 static void delayRead(int reg, u32 bpc) {
103 // SysPrintf("delayRead at %x!\n", psxRegs.pc);
105 rold = psxRegs.GPR.r[reg];
106 psxBSC[psxRegs.code >> 26](); // branch delay load
107 rnew = psxRegs.GPR.r[reg];
113 psxRegs.GPR.r[reg] = rold;
114 execI(); // first branch opcode
115 psxRegs.GPR.r[reg] = rnew;
120 static void delayWrite(int reg, u32 bpc) {
122 /* SysPrintf("delayWrite at %x!\n", psxRegs.pc);
124 SysPrintf("%s\n", disR3000AF(psxRegs.code, psxRegs.pc-4));
125 SysPrintf("%s\n", disR3000AF(PSXMu32(bpc), bpc));*/
127 // no changes from normal behavior
129 psxBSC[psxRegs.code >> 26]();
137 static void delayReadWrite(int reg, u32 bpc) {
139 // SysPrintf("delayReadWrite at %x!\n", psxRegs.pc);
141 // the branch delay load is skipped
149 // this defines shall be used with the tmp
150 // of the next func (instead of _Funct_...)
151 #define _tFunct_ ((tmp ) & 0x3F) // The funct part of the instruction register
152 #define _tRd_ ((tmp >> 11) & 0x1F) // The rd part of the instruction register
153 #define _tRt_ ((tmp >> 16) & 0x1F) // The rt part of the instruction register
154 #define _tRs_ ((tmp >> 21) & 0x1F) // The rs part of the instruction register
155 #define _tSa_ ((tmp >> 6) & 0x1F) // The sa part of the instruction register
157 int psxTestLoadDelay(int reg, u32 tmp) {
158 if (tmp == 0) return 0; // NOP
160 case 0x00: // SPECIAL
163 case 0x02: case 0x03: // SRL/SRA
164 if (_tRd_ == reg && _tRt_ == reg) return 1; else
165 if (_tRt_ == reg) return 2; else
166 if (_tRd_ == reg) return 3;
170 if (_tRs_ == reg) return 2;
173 if (_tRd_ == reg && _tRs_ == reg) return 1; else
174 if (_tRs_ == reg) return 2; else
175 if (_tRd_ == reg) return 3;
178 // SYSCALL/BREAK just a break;
180 case 0x20: case 0x21: case 0x22: case 0x23:
181 case 0x24: case 0x25: case 0x26: case 0x27:
182 case 0x2a: case 0x2b: // ADD/ADDU...
183 case 0x04: case 0x06: case 0x07: // SLLV...
184 if (_tRd_ == reg && (_tRt_ == reg || _tRs_ == reg)) return 1; else
185 if (_tRt_ == reg || _tRs_ == reg) return 2; else
186 if (_tRd_ == reg) return 3;
189 case 0x10: case 0x12: // MFHI/MFLO
190 if (_tRd_ == reg) return 3;
192 case 0x11: case 0x13: // MTHI/MTLO
193 if (_tRs_ == reg) return 2;
196 case 0x18: case 0x19:
197 case 0x1a: case 0x1b: // MULT/DIV...
198 if (_tRt_ == reg || _tRs_ == reg) return 2;
205 case 0x00: case 0x01:
206 case 0x10: case 0x11: // BLTZ/BGEZ...
207 // Xenogears - lbu v0 / beq v0
208 // - no load delay (fixes battle loading)
211 if (_tRs_ == reg) return 2;
216 // J would be just a break;
218 if (31 == reg) return 3;
221 case 0x04: case 0x05: // BEQ/BNE
222 // Xenogears - lbu v0 / beq v0
223 // - no load delay (fixes battle loading)
226 if (_tRs_ == reg || _tRt_ == reg) return 2;
229 case 0x06: case 0x07: // BLEZ/BGTZ
230 // Xenogears - lbu v0 / beq v0
231 // - no load delay (fixes battle loading)
234 if (_tRs_ == reg) return 2;
237 case 0x08: case 0x09: case 0x0a: case 0x0b:
238 case 0x0c: case 0x0d: case 0x0e: // ADDI/ADDIU...
239 if (_tRt_ == reg && _tRs_ == reg) return 1; else
240 if (_tRs_ == reg) return 2; else
241 if (_tRt_ == reg) return 3;
245 if (_tRt_ == reg) return 3;
251 if (_tRt_ == reg) return 3;
254 if (_tRt_ == reg) return 3;
257 if (_tRt_ == reg) return 2;
260 if (_tRt_ == reg) return 2;
271 if (_tRt_ == reg) return 3;
274 if (_tRt_ == reg) return 3;
277 if (_tRt_ == reg) return 2;
280 if (_tRt_ == reg) return 2;
288 case 0x22: case 0x26: // LWL/LWR
289 if (_tRt_ == reg) return 3; else
290 if (_tRs_ == reg) return 2;
293 case 0x20: case 0x21: case 0x23:
294 case 0x24: case 0x25: // LB/LH/LW/LBU/LHU
295 if (_tRt_ == reg && _tRs_ == reg) return 1; else
296 if (_tRs_ == reg) return 2; else
297 if (_tRt_ == reg) return 3;
300 case 0x28: case 0x29: case 0x2a:
301 case 0x2b: case 0x2e: // SB/SH/SWL/SW/SWR
302 if (_tRt_ == reg || _tRs_ == reg) return 2;
305 case 0x32: case 0x3a: // LWC2/SWC2
306 if (_tRs_ == reg) return 2;
313 void psxDelayTest(int reg, u32 bpc) {
314 u32 tmp = fetch(bpc);
317 switch (psxTestLoadDelay(reg, tmp)) {
319 delayReadWrite(reg, bpc); return;
321 delayRead(reg, bpc); return;
323 delayWrite(reg, bpc); return;
325 psxBSC[psxRegs.code >> 26]();
333 static u32 psxBranchNoDelay(void) {
336 psxRegs.code = fetch(psxRegs.pc);
338 case 0x00: // SPECIAL
344 if (_Rd_) { _SetLink(_Rd_); }
352 return _BranchTarget_;
355 if (_i32(_rRs_) >= 0)
356 return _BranchTarget_;
359 if (_i32(_rRs_) < 0) {
361 return _BranchTarget_;
365 if (_i32(_rRs_) >= 0) {
367 return _BranchTarget_;
378 if (_i32(_rRs_) == _i32(_rRt_))
379 return _BranchTarget_;
382 if (_i32(_rRs_) != _i32(_rRt_))
383 return _BranchTarget_;
386 if (_i32(_rRs_) <= 0)
387 return _BranchTarget_;
391 return _BranchTarget_;
398 static int psxDelayBranchExec(u32 tar) {
403 psxRegs.cycle += BIAS;
408 static int psxDelayBranchTest(u32 tar1) {
409 u32 tar2, tmp1, tmp2;
411 tar2 = psxBranchNoDelay();
418 * Branch in delay slot:
419 * - execute 1 instruction at tar1
420 * - jump to tar2 (target of branch in delay slot; this branch
421 * has no normal delay slot, instruction at tar1 was fetched instead)
424 tmp1 = psxBranchNoDelay();
425 if (tmp1 == (u32)-1) {
426 return psxDelayBranchExec(tar2);
429 psxRegs.cycle += BIAS;
432 * Got a branch at tar1:
433 * - execute 1 instruction at tar2
434 * - jump to target of that branch (tmp1)
437 tmp2 = psxBranchNoDelay();
438 if (tmp2 == (u32)-1) {
439 return psxDelayBranchExec(tmp1);
442 psxRegs.cycle += BIAS;
445 * Got a branch at tar2:
446 * - execute 1 instruction at tmp1
447 * - jump to target of that branch (tmp2)
450 return psxDelayBranchExec(tmp2);
453 static void doBranch(u32 tar) {
456 branch2 = branch = 1;
459 // check for branch in delay slot
460 if (psxDelayBranchTest(tar))
463 psxRegs.code = fetch(psxRegs.pc);
468 psxRegs.cycle += BIAS;
470 // check for load delay
471 tmp = psxRegs.code >> 26;
477 psxDelayTest(_Rt_, branchPC);
487 psxDelayTest(_Rt_, branchPC);
494 psxDelayTest(_Rt_, branchPC);
497 if (tmp >= 0x20 && tmp <= 0x26) { // LB/LH/LWL/LW/LBU/LHU/LWR
498 psxDelayTest(_Rt_, branchPC);
504 psxBSC[psxRegs.code >> 26]();
507 psxRegs.pc = branchPC;
512 /*********************************************************
513 * Arithmetic with immediate operand *
514 * Format: OP rt, rs, immediate *
515 *********************************************************/
516 void psxADDI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im (Exception on Integer Overflow)
517 void psxADDIU() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im
518 void psxANDI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) & _ImmU_; } // Rt = Rs And Im
519 void psxORI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) | _ImmU_; } // Rt = Rs Or Im
520 void psxXORI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) ^ _ImmU_; } // Rt = Rs Xor Im
521 void psxSLTI() { if (!_Rt_) return; _rRt_ = _i32(_rRs_) < _Imm_ ; } // Rt = Rs < Im (Signed)
522 void psxSLTIU() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) < ((u32)_Imm_); } // Rt = Rs < Im (Unsigned)
524 /*********************************************************
525 * Register arithmetic *
526 * Format: OP rd, rs, rt *
527 *********************************************************/
528 void psxADD() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt (Exception on Integer Overflow)
529 void psxADDU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt
530 void psxSUB() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt (Exception on Integer Overflow)
531 void psxSUBU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt
532 void psxAND() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) & _u32(_rRt_); } // Rd = Rs And Rt
533 void psxOR() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) | _u32(_rRt_); } // Rd = Rs Or Rt
534 void psxXOR() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) ^ _u32(_rRt_); } // Rd = Rs Xor Rt
535 void psxNOR() { if (!_Rd_) return; _rRd_ =~(_u32(_rRs_) | _u32(_rRt_)); }// Rd = Rs Nor Rt
536 void psxSLT() { if (!_Rd_) return; _rRd_ = _i32(_rRs_) < _i32(_rRt_); } // Rd = Rs < Rt (Signed)
537 void psxSLTU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) < _u32(_rRt_); } // Rd = Rs < Rt (Unsigned)
539 /*********************************************************
540 * Register mult/div & Register trap logic *
541 * Format: OP rs, rt *
542 *********************************************************/
545 _i32(_rHi_) = _i32(_rRs_);
546 if (_i32(_rRs_) & 0x80000000) {
549 _i32(_rLo_) = 0xFFFFFFFF;
552 * Notaz said that this was "not needed" for ARM platforms and could slow it down so let's disable for ARM.
553 * This fixes a crash issue that can happen when running Amidog's CPU test.
554 * (It still stays stuck to a black screen but at least it doesn't crash anymore)
556 #if !defined(__arm__) && !defined(__aarch64__)
557 } else if (_i32(_rRs_) == 0x80000000 && _i32(_rRt_) == 0xFFFFFFFF) {
558 _i32(_rLo_) = 0x80000000;
562 _i32(_rLo_) = _i32(_rRs_) / _i32(_rRt_);
563 _i32(_rHi_) = _i32(_rRs_) % _i32(_rRt_);
567 void psxDIV_stall() {
568 psxRegs.muldivBusyCycle = psxRegs.cycle + 37;
574 _rLo_ = _rRs_ / _rRt_;
575 _rHi_ = _rRs_ % _rRt_;
578 _i32(_rLo_) = 0xffffffff;
579 _i32(_rHi_) = _i32(_rRs_);
583 void psxDIVU_stall() {
584 psxRegs.muldivBusyCycle = psxRegs.cycle + 37;
589 u64 res = (s64)((s64)_i32(_rRs_) * (s64)_i32(_rRt_));
591 psxRegs.GPR.n.lo = (u32)(res & 0xffffffff);
592 psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff);
595 void psxMULT_stall() {
596 // approximate, but maybe good enough
598 u32 lz = __builtin_clz(((rs ^ ((s32)rs >> 21)) | 1));
599 u32 c = 7 + (2 - (lz / 11)) * 4;
600 psxRegs.muldivBusyCycle = psxRegs.cycle + c;
605 u64 res = (u64)((u64)_u32(_rRs_) * (u64)_u32(_rRt_));
607 psxRegs.GPR.n.lo = (u32)(res & 0xffffffff);
608 psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff);
611 void psxMULTU_stall() {
612 // approximate, but maybe good enough
613 u32 lz = __builtin_clz(_rRs_ | 1);
614 u32 c = 7 + (2 - (lz / 11)) * 4;
615 psxRegs.muldivBusyCycle = psxRegs.cycle + c;
619 /*********************************************************
620 * Register branch logic *
621 * Format: OP rs, offset *
622 *********************************************************/
623 #define RepZBranchi32(op) if(_i32(_rRs_) op 0) doBranch(_BranchTarget_);
624 #define RepZBranchLinki32(op) { _SetLink(31); if(_i32(_rRs_) op 0) { doBranch(_BranchTarget_); } }
626 void psxBGEZ() { RepZBranchi32(>=) } // Branch if Rs >= 0
627 void psxBGEZAL() { RepZBranchLinki32(>=) } // Branch if Rs >= 0 and link
628 void psxBGTZ() { RepZBranchi32(>) } // Branch if Rs > 0
629 void psxBLEZ() { RepZBranchi32(<=) } // Branch if Rs <= 0
630 void psxBLTZ() { RepZBranchi32(<) } // Branch if Rs < 0
631 void psxBLTZAL() { RepZBranchLinki32(<) } // Branch if Rs < 0 and link
633 /*********************************************************
634 * Shift arithmetic with constant shift *
635 * Format: OP rd, rt, sa *
636 *********************************************************/
637 void psxSLL() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) << _Sa_; } // Rd = Rt << sa
638 void psxSRA() { if (!_Rd_) return; _i32(_rRd_) = _i32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (arithmetic)
639 void psxSRL() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (logical)
641 /*********************************************************
642 * Shift arithmetic with variant register shift *
643 * Format: OP rd, rt, rs *
644 *********************************************************/
645 void psxSLLV() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) << (_u32(_rRs_) & 0x1F); } // Rd = Rt << rs
646 void psxSRAV() { if (!_Rd_) return; _i32(_rRd_) = _i32(_rRt_) >> (_u32(_rRs_) & 0x1F); } // Rd = Rt >> rs (arithmetic)
647 void psxSRLV() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) >> (_u32(_rRs_) & 0x1F); } // Rd = Rt >> rs (logical)
649 /*********************************************************
650 * Load higher 16 bits of the first word in GPR with imm *
651 * Format: OP rt, immediate *
652 *********************************************************/
653 void psxLUI() { if (!_Rt_) return; _u32(_rRt_) = psxRegs.code << 16; } // Upper halfword of Rt = Im
655 /*********************************************************
656 * Move from HI/LO to GPR *
658 *********************************************************/
659 void psxMFHI() { if (!_Rd_) return; _rRd_ = _rHi_; } // Rd = Hi
660 void psxMFLO() { if (!_Rd_) return; _rRd_ = _rLo_; } // Rd = Lo
662 static void mflohiCheckStall(void)
664 u32 left = psxRegs.muldivBusyCycle - psxRegs.cycle;
666 //printf("muldiv stall %u\n", left);
667 psxRegs.cycle = psxRegs.muldivBusyCycle;
671 void psxMFHI_stall() { mflohiCheckStall(); psxMFHI(); }
672 void psxMFLO_stall() { mflohiCheckStall(); psxMFLO(); }
674 /*********************************************************
675 * Move to GPR to HI/LO & Register jump *
677 *********************************************************/
678 void psxMTHI() { _rHi_ = _rRs_; } // Hi = Rs
679 void psxMTLO() { _rLo_ = _rRs_; } // Lo = Rs
681 /*********************************************************
682 * Special purpose instructions *
684 *********************************************************/
687 psxException(0x24, branch);
692 psxException(0x20, branch);
696 // SysPrintf("psxRFE\n");
697 psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status & 0xfffffff0) |
698 ((psxRegs.CP0.n.Status & 0x3c) >> 2);
702 /*********************************************************
703 * Register branch logic *
704 * Format: OP rs, rt, offset *
705 *********************************************************/
706 #define RepBranchi32(op) if(_i32(_rRs_) op _i32(_rRt_)) doBranch(_BranchTarget_);
708 void psxBEQ() { RepBranchi32(==) } // Branch if Rs == Rt
709 void psxBNE() { RepBranchi32(!=) } // Branch if Rs != Rt
711 /*********************************************************
713 * Format: OP target *
714 *********************************************************/
715 void psxJ() { doBranch(_JumpTarget_); }
716 void psxJAL() { _SetLink(31); doBranch(_JumpTarget_); }
718 /*********************************************************
720 * Format: OP rs, rd *
721 *********************************************************/
723 doBranch(_rRs_ & ~3);
728 u32 temp = _u32(_rRs_);
729 if (_Rd_) { _SetLink(_Rd_); }
733 /*********************************************************
734 * Load and store for GPR *
735 * Format: OP rt, offset(base) *
736 *********************************************************/
738 #define _oB_ (_u32(_rRs_) + _Imm_)
742 _i32(_rRt_) = (signed char)psxMemRead8(_oB_);
750 _u32(_rRt_) = psxMemRead8(_oB_);
758 _i32(_rRt_) = (short)psxMemRead16(_oB_);
766 _u32(_rRt_) = psxMemRead16(_oB_);
774 _u32(_rRt_) = psxMemRead32(_oB_);
780 u32 LWL_MASK[4] = { 0xffffff, 0xffff, 0xff, 0 };
781 u32 LWL_SHIFT[4] = { 24, 16, 8, 0 };
785 u32 shift = addr & 3;
786 u32 mem = psxMemRead32(addr & ~3);
789 _u32(_rRt_) = ( _u32(_rRt_) & LWL_MASK[shift]) |
790 ( mem << LWL_SHIFT[shift]);
793 Mem = 1234. Reg = abcd
795 0 4bcd (mem << 24) | (reg & 0x00ffffff)
796 1 34cd (mem << 16) | (reg & 0x0000ffff)
797 2 234d (mem << 8) | (reg & 0x000000ff)
798 3 1234 (mem ) | (reg & 0x00000000)
802 u32 LWR_MASK[4] = { 0, 0xff000000, 0xffff0000, 0xffffff00 };
803 u32 LWR_SHIFT[4] = { 0, 8, 16, 24 };
807 u32 shift = addr & 3;
808 u32 mem = psxMemRead32(addr & ~3);
811 _u32(_rRt_) = ( _u32(_rRt_) & LWR_MASK[shift]) |
812 ( mem >> LWR_SHIFT[shift]);
815 Mem = 1234. Reg = abcd
817 0 1234 (mem ) | (reg & 0x00000000)
818 1 a123 (mem >> 8) | (reg & 0xff000000)
819 2 ab12 (mem >> 16) | (reg & 0xffff0000)
820 3 abc1 (mem >> 24) | (reg & 0xffffff00)
824 void psxSB() { psxMemWrite8 (_oB_, _rRt_ & 0xff); }
825 void psxSH() { psxMemWrite16(_oB_, _rRt_ & 0xffff); }
826 void psxSW() { psxMemWrite32(_oB_, _rRt_); }
828 u32 SWL_MASK[4] = { 0xffffff00, 0xffff0000, 0xff000000, 0 };
829 u32 SWL_SHIFT[4] = { 24, 16, 8, 0 };
833 u32 shift = addr & 3;
834 u32 mem = psxMemRead32(addr & ~3);
836 psxMemWrite32(addr & ~3, (_u32(_rRt_) >> SWL_SHIFT[shift]) |
837 ( mem & SWL_MASK[shift]) );
839 Mem = 1234. Reg = abcd
841 0 123a (reg >> 24) | (mem & 0xffffff00)
842 1 12ab (reg >> 16) | (mem & 0xffff0000)
843 2 1abc (reg >> 8) | (mem & 0xff000000)
844 3 abcd (reg ) | (mem & 0x00000000)
848 u32 SWR_MASK[4] = { 0, 0xff, 0xffff, 0xffffff };
849 u32 SWR_SHIFT[4] = { 0, 8, 16, 24 };
853 u32 shift = addr & 3;
854 u32 mem = psxMemRead32(addr & ~3);
856 psxMemWrite32(addr & ~3, (_u32(_rRt_) << SWR_SHIFT[shift]) |
857 ( mem & SWR_MASK[shift]) );
860 Mem = 1234. Reg = abcd
862 0 abcd (reg ) | (mem & 0x00000000)
863 1 bcd4 (reg << 8) | (mem & 0x000000ff)
864 2 cd34 (reg << 16) | (mem & 0x0000ffff)
865 3 d234 (reg << 24) | (mem & 0x00ffffff)
869 /*********************************************************
870 * Moves between GPR and COPx *
871 * Format: OP rt, fs *
872 *********************************************************/
873 void psxMFC0() { if (!_Rt_) return; _i32(_rRt_) = (int)_rFs_; }
874 void psxCFC0() { if (!_Rt_) return; _i32(_rRt_) = (int)_rFs_; }
876 void psxTestSWInts() {
877 if (psxRegs.CP0.n.Cause & psxRegs.CP0.n.Status & 0x0300 &&
878 psxRegs.CP0.n.Status & 0x1) {
879 psxRegs.CP0.n.Cause &= ~0x7c;
880 psxException(psxRegs.CP0.n.Cause, branch);
884 void MTC0(int reg, u32 val) {
885 // SysPrintf("MTC0 %d: %x\n", reg, val);
888 psxRegs.CP0.r[12] = val;
893 psxRegs.CP0.n.Cause &= ~0x0300;
894 psxRegs.CP0.n.Cause |= val & 0x0300;
899 psxRegs.CP0.r[reg] = val;
904 void psxMTC0() { MTC0(_Rd_, _u32(_rRt_)); }
905 void psxCTC0() { MTC0(_Rd_, _u32(_rRt_)); }
907 /*********************************************************
908 * Unknow instruction (would generate an exception) *
910 *********************************************************/
913 PSXCPU_LOG("psx: Unimplemented op %x\n", psxRegs.code);
930 psxCP2[_Funct_]((struct psxCP2Regs *)&psxRegs.CP2D);
933 void psxCOP2_stall() {
936 psxCP2[f]((struct psxCP2Regs *)&psxRegs.CP2D);
939 void psxBASIC(struct psxCP2Regs *regs) {
944 // psxHLEt[psxRegs.code & 0xffff]();
945 // psxHLEt[psxRegs.code & 0x07](); // HDHOSHY experimental patch
946 uint32_t hleCode = psxRegs.code & 0x03ffffff;
947 if (hleCode >= (sizeof(psxHLEt) / sizeof(psxHLEt[0]))) {
954 void (*psxBSC[64])() = {
955 psxSPECIAL, psxREGIMM, psxJ , psxJAL , psxBEQ , psxBNE , psxBLEZ, psxBGTZ,
956 psxADDI , psxADDIU , psxSLTI, psxSLTIU, psxANDI, psxORI , psxXORI, psxLUI ,
957 psxCOP0 , psxNULL , psxCOP2, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL,
958 psxNULL , psxNULL , psxNULL, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL,
959 psxLB , psxLH , psxLWL , psxLW , psxLBU , psxLHU , psxLWR , psxNULL,
960 psxSB , psxSH , psxSWL , psxSW , psxNULL, psxNULL, psxSWR , psxNULL,
961 psxNULL , psxNULL , gteLWC2, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL,
962 psxNULL , psxNULL , gteSWC2, psxHLE , psxNULL, psxNULL, psxNULL, psxNULL
966 void (*psxSPC[64])() = {
967 psxSLL , psxNULL , psxSRL , psxSRA , psxSLLV , psxNULL , psxSRLV, psxSRAV,
968 psxJR , psxJALR , psxNULL, psxNULL, psxSYSCALL, psxBREAK, psxNULL, psxNULL,
969 psxMFHI, psxMTHI , psxMFLO, psxMTLO, psxNULL , psxNULL , psxNULL, psxNULL,
970 psxMULT, psxMULTU, psxDIV , psxDIVU, psxNULL , psxNULL , psxNULL, psxNULL,
971 psxADD , psxADDU , psxSUB , psxSUBU, psxAND , psxOR , psxXOR , psxNOR ,
972 psxNULL, psxNULL , psxSLT , psxSLTU, psxNULL , psxNULL , psxNULL, psxNULL,
973 psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL,
974 psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL
977 void (*psxREG[32])() = {
978 psxBLTZ , psxBGEZ , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
979 psxNULL , psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
980 psxBLTZAL, psxBGEZAL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
981 psxNULL , psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL
984 void (*psxCP0[32])() = {
985 psxMFC0, psxNULL, psxCFC0, psxNULL, psxMTC0, psxNULL, psxCTC0, psxNULL,
986 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
987 psxRFE , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
988 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL
991 void (*psxCP2[64])(struct psxCP2Regs *regs) = {
992 psxBASIC, gteRTPS , psxNULL , psxNULL, psxNULL, psxNULL , gteNCLIP, psxNULL, // 00
993 psxNULL , psxNULL , psxNULL , psxNULL, gteOP , psxNULL , psxNULL , psxNULL, // 08
994 gteDPCS , gteINTPL, gteMVMVA, gteNCDS, gteCDP , psxNULL , gteNCDT , psxNULL, // 10
995 psxNULL , psxNULL , psxNULL , gteNCCS, gteCC , psxNULL , gteNCS , psxNULL, // 18
996 gteNCT , psxNULL , psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, // 20
997 gteSQR , gteDCPL , gteDPCT , psxNULL, psxNULL, gteAVSZ3, gteAVSZ4, psxNULL, // 28
998 gteRTPT , psxNULL , psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, // 30
999 psxNULL , psxNULL , psxNULL , psxNULL, psxNULL, gteGPF , gteGPL , gteNCCT // 38
1002 void (*psxCP2BSC[32])() = {
1003 gteMFC2, psxNULL, gteCFC2, psxNULL, gteMTC2, psxNULL, gteCTC2, psxNULL,
1004 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
1005 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
1006 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL
1010 ///////////////////////////////////////////
1012 static int intInit() {
1016 static void intReset() {
1017 memset(&ICache, 0xff, sizeof(ICache));
1026 void intExecuteBlock() {
1028 while (!branch2) execI();
1031 static void intClear(u32 Addr, u32 Size) {
1034 void intNotify (int note, void *data) {
1035 /* Gameblabla - Only clear the icache if it's isolated */
1036 if (note == R3000ACPU_NOTIFY_CACHE_ISOLATED)
1038 memset(&ICache, 0xff, sizeof(ICache));
1042 void intApplyConfig() {
1043 assert(psxBSC[18] == psxCOP2 || psxBSC[18] == psxCOP2_stall);
1044 assert(psxBSC[50] == gteLWC2 || psxBSC[50] == gteLWC2_stall);
1045 assert(psxBSC[58] == gteSWC2 || psxBSC[58] == gteSWC2_stall);
1046 assert(psxSPC[16] == psxMFHI || psxSPC[16] == psxMFHI_stall);
1047 assert(psxSPC[18] == psxMFLO || psxSPC[18] == psxMFLO_stall);
1048 assert(psxSPC[24] == psxMULT || psxSPC[24] == psxMULT_stall);
1049 assert(psxSPC[25] == psxMULTU || psxSPC[25] == psxMULTU_stall);
1050 assert(psxSPC[26] == psxDIV || psxSPC[26] == psxDIV_stall);
1051 assert(psxSPC[27] == psxDIVU || psxSPC[27] == psxDIVU_stall);
1053 if (Config.DisableStalls) {
1054 psxBSC[18] = psxCOP2;
1055 psxBSC[50] = gteLWC2;
1056 psxBSC[58] = gteSWC2;
1057 psxSPC[16] = psxMFHI;
1058 psxSPC[18] = psxMFLO;
1059 psxSPC[24] = psxMULT;
1060 psxSPC[25] = psxMULTU;
1061 psxSPC[26] = psxDIV;
1062 psxSPC[27] = psxDIVU;
1064 psxBSC[18] = psxCOP2_stall;
1065 psxBSC[50] = gteLWC2_stall;
1066 psxBSC[58] = gteSWC2_stall;
1067 psxSPC[16] = psxMFHI_stall;
1068 psxSPC[18] = psxMFLO_stall;
1069 psxSPC[24] = psxMULT_stall;
1070 psxSPC[25] = psxMULTU_stall;
1071 psxSPC[26] = psxDIV_stall;
1072 psxSPC[27] = psxDIVU_stall;
1075 // dynarec may occasionally call the interpreter, in such a case the
1076 // cache won't work (cache only works right if all fetches go through it)
1077 if (!Config.icache_emulation || psxCpu != &psxInt)
1078 fetch = fetchNoCache;
1080 fetch = fetchICache;
1083 static void intShutdown() {
1086 // interpreter execution
1088 psxRegs.code = fetch(psxRegs.pc);
1092 if (Config.Debug) ProcessDebug();
1095 psxRegs.cycle += BIAS;
1097 psxBSC[psxRegs.code >> 26]();
1100 R3000Acpu psxInt = {