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));
47 void StartDebugger() {}
48 void ProcessDebug() {}
49 void StopDebugger() {}
57 void (*psxCP2[64])(struct psxCP2Regs *regs);
58 void (*psxCP2BSC[32])();
60 static u32 fetchNoCache(u32 pc)
62 u32 *code = (u32 *)PSXM(pc);
63 return ((code == NULL) ? 0 : SWAP32(*code));
68 Use old CPU cache code when the RAM location is updated with new code (affects in-game racing)
70 static struct cache_entry {
75 static u32 fetchICache(u32 pc)
80 // this is not how the hardware works but whatever
81 struct cache_entry *entry = &ICache[(pc & 0xff0) >> 4];
83 if (((entry->tag ^ pc) & 0xfffffff0) != 0 || pc < entry->tag)
85 u32 *code = (u32 *)PSXM(pc & ~0x0f);
90 // treat as 4 words, although other configurations are said to be possible
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]);
99 return entry->data[(pc & 0x0f) >> 2];
102 return fetchNoCache(pc);
105 u32 (*fetch)(u32 pc) = fetchNoCache;
107 static void delayRead(int reg, u32 bpc) {
110 // SysPrintf("delayRead at %x!\n", psxRegs.pc);
112 rold = psxRegs.GPR.r[reg];
113 psxBSC[psxRegs.code >> 26](); // branch delay load
114 rnew = psxRegs.GPR.r[reg];
120 psxRegs.GPR.r[reg] = rold;
121 execI(); // first branch opcode
122 psxRegs.GPR.r[reg] = rnew;
127 static void delayWrite(int reg, u32 bpc) {
129 /* SysPrintf("delayWrite at %x!\n", psxRegs.pc);
131 SysPrintf("%s\n", disR3000AF(psxRegs.code, psxRegs.pc-4));
132 SysPrintf("%s\n", disR3000AF(PSXMu32(bpc), bpc));*/
134 // no changes from normal behavior
136 psxBSC[psxRegs.code >> 26]();
144 static void delayReadWrite(int reg, u32 bpc) {
146 // SysPrintf("delayReadWrite at %x!\n", psxRegs.pc);
148 // the branch delay load is skipped
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
164 int psxTestLoadDelay(int reg, u32 tmp) {
165 if (tmp == 0) return 0; // NOP
167 case 0x00: // SPECIAL
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;
177 if (_tRs_ == reg) return 2;
180 if (_tRd_ == reg && _tRs_ == reg) return 1; else
181 if (_tRs_ == reg) return 2; else
182 if (_tRd_ == reg) return 3;
185 // SYSCALL/BREAK just a break;
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;
196 case 0x10: case 0x12: // MFHI/MFLO
197 if (_tRd_ == reg) return 3;
199 case 0x11: case 0x13: // MTHI/MTLO
200 if (_tRs_ == reg) return 2;
203 case 0x18: case 0x19:
204 case 0x1a: case 0x1b: // MULT/DIV...
205 if (_tRt_ == reg || _tRs_ == reg) return 2;
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)
218 if (_tRs_ == reg) return 2;
223 // J would be just a break;
225 if (31 == reg) return 3;
228 case 0x04: case 0x05: // BEQ/BNE
229 // Xenogears - lbu v0 / beq v0
230 // - no load delay (fixes battle loading)
233 if (_tRs_ == reg || _tRt_ == reg) return 2;
236 case 0x06: case 0x07: // BLEZ/BGTZ
237 // Xenogears - lbu v0 / beq v0
238 // - no load delay (fixes battle loading)
241 if (_tRs_ == reg) return 2;
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;
252 if (_tRt_ == reg) return 3;
258 if (_tRt_ == reg) return 3;
261 if (_tRt_ == reg) return 3;
264 if (_tRt_ == reg) return 2;
267 if (_tRt_ == reg) return 2;
278 if (_tRt_ == reg) return 3;
281 if (_tRt_ == reg) return 3;
284 if (_tRt_ == reg) return 2;
287 if (_tRt_ == reg) return 2;
295 case 0x22: case 0x26: // LWL/LWR
296 if (_tRt_ == reg) return 3; else
297 if (_tRs_ == reg) return 2;
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;
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;
312 case 0x32: case 0x3a: // LWC2/SWC2
313 if (_tRs_ == reg) return 2;
320 void psxDelayTest(int reg, u32 bpc) {
321 u32 tmp = fetch(psxRegs.pc);
324 switch (psxTestLoadDelay(reg, tmp)) {
326 delayReadWrite(reg, bpc); return;
328 delayRead(reg, bpc); return;
330 delayWrite(reg, bpc); return;
332 psxBSC[psxRegs.code >> 26]();
340 static u32 psxBranchNoDelay(void) {
343 psxRegs.code = fetch(psxRegs.pc);
345 case 0x00: // SPECIAL
351 if (_Rd_) { _SetLink(_Rd_); }
359 return _BranchTarget_;
362 if (_i32(_rRs_) >= 0)
363 return _BranchTarget_;
366 if (_i32(_rRs_) < 0) {
368 return _BranchTarget_;
372 if (_i32(_rRs_) >= 0) {
374 return _BranchTarget_;
385 if (_i32(_rRs_) == _i32(_rRt_))
386 return _BranchTarget_;
389 if (_i32(_rRs_) != _i32(_rRt_))
390 return _BranchTarget_;
393 if (_i32(_rRs_) <= 0)
394 return _BranchTarget_;
398 return _BranchTarget_;
405 static int psxDelayBranchExec(u32 tar) {
410 psxRegs.cycle += BIAS;
415 static int psxDelayBranchTest(u32 tar1) {
416 u32 tar2, tmp1, tmp2;
418 tar2 = psxBranchNoDelay();
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)
431 tmp1 = psxBranchNoDelay();
432 if (tmp1 == (u32)-1) {
433 return psxDelayBranchExec(tar2);
436 psxRegs.cycle += BIAS;
439 * Got a branch at tar1:
440 * - execute 1 instruction at tar2
441 * - jump to target of that branch (tmp1)
444 tmp2 = psxBranchNoDelay();
445 if (tmp2 == (u32)-1) {
446 return psxDelayBranchExec(tmp1);
449 psxRegs.cycle += BIAS;
452 * Got a branch at tar2:
453 * - execute 1 instruction at tmp1
454 * - jump to target of that branch (tmp2)
457 return psxDelayBranchExec(tmp2);
460 static void doBranch(u32 tar) {
463 branch2 = branch = 1;
466 // check for branch in delay slot
467 if (psxDelayBranchTest(tar))
470 psxRegs.code = fetch(psxRegs.pc);
475 psxRegs.cycle += BIAS;
477 // check for load delay
478 tmp = psxRegs.code >> 26;
484 psxDelayTest(_Rt_, branchPC);
494 psxDelayTest(_Rt_, branchPC);
501 psxDelayTest(_Rt_, branchPC);
504 if (tmp >= 0x20 && tmp <= 0x26) { // LB/LH/LWL/LW/LBU/LHU/LWR
505 psxDelayTest(_Rt_, branchPC);
511 psxBSC[psxRegs.code >> 26]();
514 psxRegs.pc = branchPC;
519 /*********************************************************
520 * Arithmetic with immediate operand *
521 * Format: OP rt, rs, immediate *
522 *********************************************************/
523 void psxADDI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im (Exception on Integer Overflow)
524 void psxADDIU() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im
525 void psxANDI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) & _ImmU_; } // Rt = Rs And Im
526 void psxORI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) | _ImmU_; } // Rt = Rs Or Im
527 void psxXORI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) ^ _ImmU_; } // Rt = Rs Xor Im
528 void psxSLTI() { if (!_Rt_) return; _rRt_ = _i32(_rRs_) < _Imm_ ; } // Rt = Rs < Im (Signed)
529 void psxSLTIU() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) < ((u32)_Imm_); } // Rt = Rs < Im (Unsigned)
531 /*********************************************************
532 * Register arithmetic *
533 * Format: OP rd, rs, rt *
534 *********************************************************/
535 void psxADD() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt (Exception on Integer Overflow)
536 void psxADDU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt
537 void psxSUB() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt (Exception on Integer Overflow)
538 void psxSUBU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt
539 void psxAND() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) & _u32(_rRt_); } // Rd = Rs And Rt
540 void psxOR() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) | _u32(_rRt_); } // Rd = Rs Or Rt
541 void psxXOR() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) ^ _u32(_rRt_); } // Rd = Rs Xor Rt
542 void psxNOR() { if (!_Rd_) return; _rRd_ =~(_u32(_rRs_) | _u32(_rRt_)); }// Rd = Rs Nor Rt
543 void psxSLT() { if (!_Rd_) return; _rRd_ = _i32(_rRs_) < _i32(_rRt_); } // Rd = Rs < Rt (Signed)
544 void psxSLTU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) < _u32(_rRt_); } // Rd = Rs < Rt (Unsigned)
546 /*********************************************************
547 * Register mult/div & Register trap logic *
548 * Format: OP rs, rt *
549 *********************************************************/
552 _i32(_rHi_) = _i32(_rRs_);
553 if (_i32(_rRs_) & 0x80000000) {
556 _i32(_rLo_) = 0xFFFFFFFF;
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)
563 #if !defined(__arm__) && !defined(__aarch64__)
564 } else if (_i32(_rRs_) == 0x80000000 && _i32(_rRt_) == 0xFFFFFFFF) {
565 _i32(_rLo_) = 0x80000000;
569 _i32(_rLo_) = _i32(_rRs_) / _i32(_rRt_);
570 _i32(_rHi_) = _i32(_rRs_) % _i32(_rRt_);
574 void psxDIV_stall() {
575 psxRegs.muldivBusyCycle = psxRegs.cycle + 37;
581 _rLo_ = _rRs_ / _rRt_;
582 _rHi_ = _rRs_ % _rRt_;
585 _i32(_rLo_) = 0xffffffff;
586 _i32(_rHi_) = _i32(_rRs_);
590 void psxDIVU_stall() {
591 psxRegs.muldivBusyCycle = psxRegs.cycle + 37;
596 u64 res = (s64)((s64)_i32(_rRs_) * (s64)_i32(_rRt_));
598 psxRegs.GPR.n.lo = (u32)(res & 0xffffffff);
599 psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff);
602 void psxMULT_stall() {
603 // approximate, but maybe good enough
605 u32 lz = __builtin_clz(((rs ^ ((s32)rs >> 21)) | 1));
606 u32 c = 7 + (2 - (lz / 11)) * 4;
607 psxRegs.muldivBusyCycle = psxRegs.cycle + c;
612 u64 res = (u64)((u64)_u32(_rRs_) * (u64)_u32(_rRt_));
614 psxRegs.GPR.n.lo = (u32)(res & 0xffffffff);
615 psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff);
618 void 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;
626 /*********************************************************
627 * Register branch logic *
628 * Format: OP rs, offset *
629 *********************************************************/
630 #define RepZBranchi32(op) if(_i32(_rRs_) op 0) doBranch(_BranchTarget_);
631 #define RepZBranchLinki32(op) { _SetLink(31); if(_i32(_rRs_) op 0) { doBranch(_BranchTarget_); } }
633 void psxBGEZ() { RepZBranchi32(>=) } // Branch if Rs >= 0
634 void psxBGEZAL() { RepZBranchLinki32(>=) } // Branch if Rs >= 0 and link
635 void psxBGTZ() { RepZBranchi32(>) } // Branch if Rs > 0
636 void psxBLEZ() { RepZBranchi32(<=) } // Branch if Rs <= 0
637 void psxBLTZ() { RepZBranchi32(<) } // Branch if Rs < 0
638 void psxBLTZAL() { RepZBranchLinki32(<) } // Branch if Rs < 0 and link
640 /*********************************************************
641 * Shift arithmetic with constant shift *
642 * Format: OP rd, rt, sa *
643 *********************************************************/
644 void psxSLL() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) << _Sa_; } // Rd = Rt << sa
645 void psxSRA() { if (!_Rd_) return; _i32(_rRd_) = _i32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (arithmetic)
646 void psxSRL() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (logical)
648 /*********************************************************
649 * Shift arithmetic with variant register shift *
650 * Format: OP rd, rt, rs *
651 *********************************************************/
652 void psxSLLV() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) << (_u32(_rRs_) & 0x1F); } // Rd = Rt << rs
653 void psxSRAV() { if (!_Rd_) return; _i32(_rRd_) = _i32(_rRt_) >> (_u32(_rRs_) & 0x1F); } // Rd = Rt >> rs (arithmetic)
654 void psxSRLV() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) >> (_u32(_rRs_) & 0x1F); } // Rd = Rt >> rs (logical)
656 /*********************************************************
657 * Load higher 16 bits of the first word in GPR with imm *
658 * Format: OP rt, immediate *
659 *********************************************************/
660 void psxLUI() { if (!_Rt_) return; _u32(_rRt_) = psxRegs.code << 16; } // Upper halfword of Rt = Im
662 /*********************************************************
663 * Move from HI/LO to GPR *
665 *********************************************************/
666 void psxMFHI() { if (!_Rd_) return; _rRd_ = _rHi_; } // Rd = Hi
667 void psxMFLO() { if (!_Rd_) return; _rRd_ = _rLo_; } // Rd = Lo
669 static void mflohiCheckStall(void)
671 u32 left = psxRegs.muldivBusyCycle - psxRegs.cycle;
673 //printf("muldiv stall %u\n", left);
674 psxRegs.cycle = psxRegs.muldivBusyCycle;
678 void psxMFHI_stall() { mflohiCheckStall(); psxMFHI(); }
679 void psxMFLO_stall() { mflohiCheckStall(); psxMFLO(); }
681 /*********************************************************
682 * Move to GPR to HI/LO & Register jump *
684 *********************************************************/
685 void psxMTHI() { _rHi_ = _rRs_; } // Hi = Rs
686 void psxMTLO() { _rLo_ = _rRs_; } // Lo = Rs
688 /*********************************************************
689 * Special purpose instructions *
691 *********************************************************/
694 psxException(0x24, branch);
699 psxException(0x20, branch);
703 // SysPrintf("psxRFE\n");
704 psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status & 0xfffffff0) |
705 ((psxRegs.CP0.n.Status & 0x3c) >> 2);
709 /*********************************************************
710 * Register branch logic *
711 * Format: OP rs, rt, offset *
712 *********************************************************/
713 #define RepBranchi32(op) if(_i32(_rRs_) op _i32(_rRt_)) doBranch(_BranchTarget_);
715 void psxBEQ() { RepBranchi32(==) } // Branch if Rs == Rt
716 void psxBNE() { RepBranchi32(!=) } // Branch if Rs != Rt
718 /*********************************************************
720 * Format: OP target *
721 *********************************************************/
722 void psxJ() { doBranch(_JumpTarget_); }
723 void psxJAL() { _SetLink(31); doBranch(_JumpTarget_); }
725 /*********************************************************
727 * Format: OP rs, rd *
728 *********************************************************/
730 doBranch(_rRs_ & ~3);
735 u32 temp = _u32(_rRs_);
736 if (_Rd_) { _SetLink(_Rd_); }
740 /*********************************************************
741 * Load and store for GPR *
742 * Format: OP rt, offset(base) *
743 *********************************************************/
745 #define _oB_ (_u32(_rRs_) + _Imm_)
749 _i32(_rRt_) = (signed char)psxMemRead8(_oB_);
757 _u32(_rRt_) = psxMemRead8(_oB_);
765 _i32(_rRt_) = (short)psxMemRead16(_oB_);
773 _u32(_rRt_) = psxMemRead16(_oB_);
781 _u32(_rRt_) = psxMemRead32(_oB_);
787 u32 LWL_MASK[4] = { 0xffffff, 0xffff, 0xff, 0 };
788 u32 LWL_SHIFT[4] = { 24, 16, 8, 0 };
792 u32 shift = addr & 3;
793 u32 mem = psxMemRead32(addr & ~3);
796 _u32(_rRt_) = ( _u32(_rRt_) & LWL_MASK[shift]) |
797 ( mem << LWL_SHIFT[shift]);
800 Mem = 1234. Reg = abcd
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)
809 u32 LWR_MASK[4] = { 0, 0xff000000, 0xffff0000, 0xffffff00 };
810 u32 LWR_SHIFT[4] = { 0, 8, 16, 24 };
814 u32 shift = addr & 3;
815 u32 mem = psxMemRead32(addr & ~3);
818 _u32(_rRt_) = ( _u32(_rRt_) & LWR_MASK[shift]) |
819 ( mem >> LWR_SHIFT[shift]);
822 Mem = 1234. Reg = abcd
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)
831 void psxSB() { psxMemWrite8 (_oB_, _rRt_ & 0xff); }
832 void psxSH() { psxMemWrite16(_oB_, _rRt_ & 0xffff); }
833 void psxSW() { psxMemWrite32(_oB_, _rRt_); }
835 u32 SWL_MASK[4] = { 0xffffff00, 0xffff0000, 0xff000000, 0 };
836 u32 SWL_SHIFT[4] = { 24, 16, 8, 0 };
840 u32 shift = addr & 3;
841 u32 mem = psxMemRead32(addr & ~3);
843 psxMemWrite32(addr & ~3, (_u32(_rRt_) >> SWL_SHIFT[shift]) |
844 ( mem & SWL_MASK[shift]) );
846 Mem = 1234. Reg = abcd
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)
855 u32 SWR_MASK[4] = { 0, 0xff, 0xffff, 0xffffff };
856 u32 SWR_SHIFT[4] = { 0, 8, 16, 24 };
860 u32 shift = addr & 3;
861 u32 mem = psxMemRead32(addr & ~3);
863 psxMemWrite32(addr & ~3, (_u32(_rRt_) << SWR_SHIFT[shift]) |
864 ( mem & SWR_MASK[shift]) );
867 Mem = 1234. Reg = abcd
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)
876 /*********************************************************
877 * Moves between GPR and COPx *
878 * Format: OP rt, fs *
879 *********************************************************/
880 void psxMFC0() { if (!_Rt_) return; _i32(_rRt_) = (int)_rFs_; }
881 void psxCFC0() { if (!_Rt_) return; _i32(_rRt_) = (int)_rFs_; }
883 void psxTestSWInts() {
884 if (psxRegs.CP0.n.Cause & psxRegs.CP0.n.Status & 0x0300 &&
885 psxRegs.CP0.n.Status & 0x1) {
886 psxRegs.CP0.n.Cause &= ~0x7c;
887 psxException(psxRegs.CP0.n.Cause, branch);
891 void MTC0(int reg, u32 val) {
892 // SysPrintf("MTC0 %d: %x\n", reg, val);
895 psxRegs.CP0.r[12] = val;
900 psxRegs.CP0.n.Cause &= ~0x0300;
901 psxRegs.CP0.n.Cause |= val & 0x0300;
906 psxRegs.CP0.r[reg] = val;
911 void psxMTC0() { MTC0(_Rd_, _u32(_rRt_)); }
912 void psxCTC0() { MTC0(_Rd_, _u32(_rRt_)); }
914 /*********************************************************
915 * Unknow instruction (would generate an exception) *
917 *********************************************************/
920 PSXCPU_LOG("psx: Unimplemented op %x\n", psxRegs.code);
937 psxCP2[_Funct_]((struct psxCP2Regs *)&psxRegs.CP2D);
940 void psxCOP2_stall() {
943 psxCP2[f]((struct psxCP2Regs *)&psxRegs.CP2D);
946 void psxBASIC(struct psxCP2Regs *regs) {
951 // psxHLEt[psxRegs.code & 0xffff]();
952 // psxHLEt[psxRegs.code & 0x07](); // HDHOSHY experimental patch
953 uint32_t hleCode = psxRegs.code & 0x03ffffff;
954 if (hleCode >= (sizeof(psxHLEt) / sizeof(psxHLEt[0]))) {
961 void (*psxBSC[64])() = {
962 psxSPECIAL, psxREGIMM, psxJ , psxJAL , psxBEQ , psxBNE , psxBLEZ, psxBGTZ,
963 psxADDI , psxADDIU , psxSLTI, psxSLTIU, psxANDI, psxORI , psxXORI, psxLUI ,
964 psxCOP0 , psxNULL , psxCOP2, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL,
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
973 void (*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
984 void (*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
991 void (*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
998 void (*psxCP2[64])(struct psxCP2Regs *regs) = {
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
1009 void (*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
1017 ///////////////////////////////////////////
1019 static int intInit() {
1023 static void intReset() {
1024 memset(&ICache, 0xff, sizeof(ICache));
1033 void intExecuteBlock() {
1035 while (!branch2) execI();
1038 static void intClear(u32 Addr, u32 Size) {
1041 void intNotify (int note, void *data) {
1042 /* Gameblabla - Only clear the icache if it's isolated */
1043 if (note == R3000ACPU_NOTIFY_CACHE_ISOLATED)
1045 memset(&ICache, 0xff, sizeof(ICache));
1049 void 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);
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;
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;
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;
1087 fetch = fetchICache;
1090 static void intShutdown() {
1093 // interpreter execution
1095 psxRegs.code = fetch(psxRegs.pc);
1099 if (Config.Debug) ProcessDebug();
1102 psxRegs.cycle += BIAS;
1104 psxBSC[psxRegs.code >> 26]();
1107 R3000Acpu psxInt = {