diff options
Diffstat (limited to 'libpcsxcore/psxinterpreter.c')
| -rwxr-xr-x[-rw-r--r--] | libpcsxcore/psxinterpreter.c | 2222 |
1 files changed, 1111 insertions, 1111 deletions
diff --git a/libpcsxcore/psxinterpreter.c b/libpcsxcore/psxinterpreter.c index 6b0d3e4c..eaa30004 100644..100755 --- a/libpcsxcore/psxinterpreter.c +++ b/libpcsxcore/psxinterpreter.c @@ -1,1111 +1,1111 @@ -/***************************************************************************
- * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the *
- * Free Software Foundation, Inc., *
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
- ***************************************************************************/
-
-/*
- * PSX assembly interpreter.
- */
-
-#include "psxcommon.h"
-#include "r3000a.h"
-#include "gte.h"
-#include "psxhle.h"
-
-static int branch = 0;
-static int branch2 = 0;
-static u32 branchPC;
-
-// These macros are used to assemble the repassembler functions
-
-#ifdef PSXCPU_LOG
-#define debugI() PSXCPU_LOG("%s\n", disR3000AF(psxRegs.code, psxRegs.pc));
-#else
-#define debugI()
-#endif
-
-static inline void execI();
-
-// Subsets
-void (*psxBSC[64])();
-void (*psxSPC[64])();
-void (*psxREG[32])();
-void (*psxCP0[32])();
-void (*psxCP2[64])();
-void (*psxCP2BSC[32])();
-
-static void delayRead(int reg, u32 bpc) {
- u32 rold, rnew;
-
-// SysPrintf("delayRead at %x!\n", psxRegs.pc);
-
- rold = psxRegs.GPR.r[reg];
- psxBSC[psxRegs.code >> 26](); // branch delay load
- rnew = psxRegs.GPR.r[reg];
-
- psxRegs.pc = bpc;
-
- branch = 0;
-
- psxRegs.GPR.r[reg] = rold;
- execI(); // first branch opcode
- psxRegs.GPR.r[reg] = rnew;
-
- psxBranchTest();
-}
-
-static void delayWrite(int reg, u32 bpc) {
-
-/* SysPrintf("delayWrite at %x!\n", psxRegs.pc);
-
- SysPrintf("%s\n", disR3000AF(psxRegs.code, psxRegs.pc-4));
- SysPrintf("%s\n", disR3000AF(PSXMu32(bpc), bpc));*/
-
- // no changes from normal behavior
-
- psxBSC[psxRegs.code >> 26]();
-
- branch = 0;
- psxRegs.pc = bpc;
-
- psxBranchTest();
-}
-
-static void delayReadWrite(int reg, u32 bpc) {
-
-// SysPrintf("delayReadWrite at %x!\n", psxRegs.pc);
-
- // the branch delay load is skipped
-
- branch = 0;
- psxRegs.pc = bpc;
-
- psxBranchTest();
-}
-
-// this defines shall be used with the tmp
-// of the next func (instead of _Funct_...)
-#define _tFunct_ ((tmp ) & 0x3F) // The funct part of the instruction register
-#define _tRd_ ((tmp >> 11) & 0x1F) // The rd part of the instruction register
-#define _tRt_ ((tmp >> 16) & 0x1F) // The rt part of the instruction register
-#define _tRs_ ((tmp >> 21) & 0x1F) // The rs part of the instruction register
-#define _tSa_ ((tmp >> 6) & 0x1F) // The sa part of the instruction register
-
-int psxTestLoadDelay(int reg, u32 tmp) {
- if (tmp == 0) return 0; // NOP
- switch (tmp >> 26) {
- case 0x00: // SPECIAL
- switch (_tFunct_) {
- case 0x00: // SLL
- case 0x02: case 0x03: // SRL/SRA
- if (_tRd_ == reg && _tRt_ == reg) return 1; else
- if (_tRt_ == reg) return 2; else
- if (_tRd_ == reg) return 3;
- break;
-
- case 0x08: // JR
- if (_tRs_ == reg) return 2;
- break;
- case 0x09: // JALR
- if (_tRd_ == reg && _tRs_ == reg) return 1; else
- if (_tRs_ == reg) return 2; else
- if (_tRd_ == reg) return 3;
- break;
-
- // SYSCALL/BREAK just a break;
-
- case 0x20: case 0x21: case 0x22: case 0x23:
- case 0x24: case 0x25: case 0x26: case 0x27:
- case 0x2a: case 0x2b: // ADD/ADDU...
- case 0x04: case 0x06: case 0x07: // SLLV...
- if (_tRd_ == reg && (_tRt_ == reg || _tRs_ == reg)) return 1; else
- if (_tRt_ == reg || _tRs_ == reg) return 2; else
- if (_tRd_ == reg) return 3;
- break;
-
- case 0x10: case 0x12: // MFHI/MFLO
- if (_tRd_ == reg) return 3;
- break;
- case 0x11: case 0x13: // MTHI/MTLO
- if (_tRs_ == reg) return 2;
- break;
-
- case 0x18: case 0x19:
- case 0x1a: case 0x1b: // MULT/DIV...
- if (_tRt_ == reg || _tRs_ == reg) return 2;
- break;
- }
- break;
-
- case 0x01: // REGIMM
- switch (_tRt_) {
- case 0x00: case 0x01:
- case 0x10: case 0x11: // BLTZ/BGEZ...
- // Xenogears - lbu v0 / beq v0
- // - no load delay (fixes battle loading)
- break;
-
- if (_tRs_ == reg) return 2;
- break;
- }
- break;
-
- // J would be just a break;
- case 0x03: // JAL
- if (31 == reg) return 3;
- break;
-
- case 0x04: case 0x05: // BEQ/BNE
- // Xenogears - lbu v0 / beq v0
- // - no load delay (fixes battle loading)
- break;
-
- if (_tRs_ == reg || _tRt_ == reg) return 2;
- break;
-
- case 0x06: case 0x07: // BLEZ/BGTZ
- // Xenogears - lbu v0 / beq v0
- // - no load delay (fixes battle loading)
- break;
-
- if (_tRs_ == reg) return 2;
- break;
-
- case 0x08: case 0x09: case 0x0a: case 0x0b:
- case 0x0c: case 0x0d: case 0x0e: // ADDI/ADDIU...
- if (_tRt_ == reg && _tRs_ == reg) return 1; else
- if (_tRs_ == reg) return 2; else
- if (_tRt_ == reg) return 3;
- break;
-
- case 0x0f: // LUI
- if (_tRt_ == reg) return 3;
- break;
-
- case 0x10: // COP0
- switch (_tFunct_) {
- case 0x00: // MFC0
- if (_tRt_ == reg) return 3;
- break;
- case 0x02: // CFC0
- if (_tRt_ == reg) return 3;
- break;
- case 0x04: // MTC0
- if (_tRt_ == reg) return 2;
- break;
- case 0x06: // CTC0
- if (_tRt_ == reg) return 2;
- break;
- // RFE just a break;
- }
- break;
-
- case 0x12: // COP2
- switch (_tFunct_) {
- case 0x00:
- switch (_tRs_) {
- case 0x00: // MFC2
- if (_tRt_ == reg) return 3;
- break;
- case 0x02: // CFC2
- if (_tRt_ == reg) return 3;
- break;
- case 0x04: // MTC2
- if (_tRt_ == reg) return 2;
- break;
- case 0x06: // CTC2
- if (_tRt_ == reg) return 2;
- break;
- }
- break;
- // RTPS... break;
- }
- break;
-
- case 0x22: case 0x26: // LWL/LWR
- if (_tRt_ == reg) return 3; else
- if (_tRs_ == reg) return 2;
- break;
-
- case 0x20: case 0x21: case 0x23:
- case 0x24: case 0x25: // LB/LH/LW/LBU/LHU
- if (_tRt_ == reg && _tRs_ == reg) return 1; else
- if (_tRs_ == reg) return 2; else
- if (_tRt_ == reg) return 3;
- break;
-
- case 0x28: case 0x29: case 0x2a:
- case 0x2b: case 0x2e: // SB/SH/SWL/SW/SWR
- if (_tRt_ == reg || _tRs_ == reg) return 2;
- break;
-
- case 0x32: case 0x3a: // LWC2/SWC2
- if (_tRs_ == reg) return 2;
- break;
- }
-
- return 0;
-}
-
-void psxDelayTest(int reg, u32 bpc) {
- u32 *code;
- u32 tmp;
-
- // Don't execute yet - just peek
- code = Read_ICache(bpc, TRUE);
-
- tmp = ((code == NULL) ? 0 : SWAP32(*code));
- branch = 1;
-
- switch (psxTestLoadDelay(reg, tmp)) {
- case 1:
- delayReadWrite(reg, bpc); return;
- case 2:
- delayRead(reg, bpc); return;
- case 3:
- delayWrite(reg, bpc); return;
- }
- psxBSC[psxRegs.code >> 26]();
-
- branch = 0;
- psxRegs.pc = bpc;
-
- psxBranchTest();
-}
-
-static u32 psxBranchNoDelay(void) {
- u32 *code;
- u32 temp;
-
- code = Read_ICache(psxRegs.pc, TRUE);
- psxRegs.code = ((code == NULL) ? 0 : SWAP32(*code));
- switch (_Op_) {
- case 0x00: // SPECIAL
- switch (_Funct_) {
- case 0x08: // JR
- return _u32(_rRs_);
- case 0x09: // JALR
- temp = _u32(_rRs_);
- if (_Rd_) { _SetLink(_Rd_); }
- return temp;
- }
- break;
- case 0x01: // REGIMM
- switch (_Rt_) {
- case 0x00: // BLTZ
- if (_i32(_rRs_) < 0)
- return _BranchTarget_;
- break;
- case 0x01: // BGEZ
- if (_i32(_rRs_) >= 0)
- return _BranchTarget_;
- break;
- case 0x08: // BLTZAL
- if (_i32(_rRs_) < 0) {
- _SetLink(31);
- return _BranchTarget_;
- }
- break;
- case 0x09: // BGEZAL
- if (_i32(_rRs_) >= 0) {
- _SetLink(31);
- return _BranchTarget_;
- }
- break;
- }
- break;
- case 0x02: // J
- return _JumpTarget_;
- case 0x03: // JAL
- _SetLink(31);
- return _JumpTarget_;
- case 0x04: // BEQ
- if (_i32(_rRs_) == _i32(_rRt_))
- return _BranchTarget_;
- break;
- case 0x05: // BNE
- if (_i32(_rRs_) != _i32(_rRt_))
- return _BranchTarget_;
- break;
- case 0x06: // BLEZ
- if (_i32(_rRs_) <= 0)
- return _BranchTarget_;
- break;
- case 0x07: // BGTZ
- if (_i32(_rRs_) > 0)
- return _BranchTarget_;
- break;
- }
-
- return (u32)-1;
-}
-
-static int psxDelayBranchExec(u32 tar) {
- execI();
-
- branch = 0;
- psxRegs.pc = tar;
- psxRegs.cycle += BIAS;
- psxBranchTest();
- return 1;
-}
-
-static int psxDelayBranchTest(u32 tar1) {
- u32 tar2, tmp1, tmp2;
-
- tar2 = psxBranchNoDelay();
- if (tar2 == (u32)-1)
- return 0;
-
- debugI();
-
- /*
- * Branch in delay slot:
- * - execute 1 instruction at tar1
- * - jump to tar2 (target of branch in delay slot; this branch
- * has no normal delay slot, instruction at tar1 was fetched instead)
- */
- psxRegs.pc = tar1;
- tmp1 = psxBranchNoDelay();
- if (tmp1 == (u32)-1) {
- return psxDelayBranchExec(tar2);
- }
- debugI();
- psxRegs.cycle += BIAS;
-
- /*
- * Got a branch at tar1:
- * - execute 1 instruction at tar2
- * - jump to target of that branch (tmp1)
- */
- psxRegs.pc = tar2;
- tmp2 = psxBranchNoDelay();
- if (tmp2 == (u32)-1) {
- return psxDelayBranchExec(tmp1);
- }
- debugI();
- psxRegs.cycle += BIAS;
-
- /*
- * Got a branch at tar2:
- * - execute 1 instruction at tmp1
- * - jump to target of that branch (tmp2)
- */
- psxRegs.pc = tmp1;
- return psxDelayBranchExec(tmp2);
-}
-
-static __inline void doBranch(u32 tar) {
- u32 *code;
- u32 tmp;
-
- branch2 = branch = 1;
- branchPC = tar;
-
- // notaz: check for branch in delay slot
- if (psxDelayBranchTest(tar))
- return;
-
- // branch delay slot
- code = Read_ICache(psxRegs.pc, TRUE);
-
- psxRegs.code = ((code == NULL) ? 0 : SWAP32(*code));
-
- debugI();
-
- psxRegs.pc += 4;
- psxRegs.cycle += BIAS;
-
- // check for load delay
- tmp = psxRegs.code >> 26;
- switch (tmp) {
- case 0x10: // COP0
- switch (_Rs_) {
- case 0x00: // MFC0
- case 0x02: // CFC0
- psxDelayTest(_Rt_, branchPC);
- return;
- }
- break;
- case 0x12: // COP2
- switch (_Funct_) {
- case 0x00:
- switch (_Rs_) {
- case 0x00: // MFC2
- case 0x02: // CFC2
- psxDelayTest(_Rt_, branchPC);
- return;
- }
- break;
- }
- break;
- case 0x32: // LWC2
- psxDelayTest(_Rt_, branchPC);
- return;
- default:
- if (tmp >= 0x20 && tmp <= 0x26) { // LB/LH/LWL/LW/LBU/LHU/LWR
- psxDelayTest(_Rt_, branchPC);
- return;
- }
- break;
- }
-
- psxBSC[psxRegs.code >> 26]();
-
- branch = 0;
- psxRegs.pc = branchPC;
-
- psxBranchTest();
-}
-
-/*********************************************************
-* Arithmetic with immediate operand *
-* Format: OP rt, rs, immediate *
-*********************************************************/
-void psxADDI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im (Exception on Integer Overflow)
-void psxADDIU() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im
-void psxANDI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) & _ImmU_; } // Rt = Rs And Im
-void psxORI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) | _ImmU_; } // Rt = Rs Or Im
-void psxXORI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) ^ _ImmU_; } // Rt = Rs Xor Im
-void psxSLTI() { if (!_Rt_) return; _rRt_ = _i32(_rRs_) < _Imm_ ; } // Rt = Rs < Im (Signed)
-void psxSLTIU() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) < ((u32)_Imm_); } // Rt = Rs < Im (Unsigned)
-
-/*********************************************************
-* Register arithmetic *
-* Format: OP rd, rs, rt *
-*********************************************************/
-void psxADD() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt (Exception on Integer Overflow)
-void psxADDU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt
-void psxSUB() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt (Exception on Integer Overflow)
-void psxSUBU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt
-void psxAND() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) & _u32(_rRt_); } // Rd = Rs And Rt
-void psxOR() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) | _u32(_rRt_); } // Rd = Rs Or Rt
-void psxXOR() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) ^ _u32(_rRt_); } // Rd = Rs Xor Rt
-void psxNOR() { if (!_Rd_) return; _rRd_ =~(_u32(_rRs_) | _u32(_rRt_)); }// Rd = Rs Nor Rt
-void psxSLT() { if (!_Rd_) return; _rRd_ = _i32(_rRs_) < _i32(_rRt_); } // Rd = Rs < Rt (Signed)
-void psxSLTU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) < _u32(_rRt_); } // Rd = Rs < Rt (Unsigned)
-
-/*********************************************************
-* Register mult/div & Register trap logic *
-* Format: OP rs, rt *
-*********************************************************/
-void psxDIV() {
- if (_i32(_rRt_) != 0) {
- _i32(_rLo_) = _i32(_rRs_) / _i32(_rRt_);
- _i32(_rHi_) = _i32(_rRs_) % _i32(_rRt_);
- }
- else {
- _i32(_rLo_) = 0xffffffff;
- _i32(_rHi_) = _i32(_rRs_);
- }
-}
-
-void psxDIVU() {
- if (_rRt_ != 0) {
- _rLo_ = _rRs_ / _rRt_;
- _rHi_ = _rRs_ % _rRt_;
- }
- else {
- _rLo_ = 0xffffffff;
- _rHi_ = _rRs_;
- }
-}
-
-void psxMULT() {
- u64 res = (s64)((s64)_i32(_rRs_) * (s64)_i32(_rRt_));
-
- psxRegs.GPR.n.lo = (u32)(res & 0xffffffff);
- psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff);
-}
-
-void psxMULTU() {
- u64 res = (u64)((u64)_u32(_rRs_) * (u64)_u32(_rRt_));
-
- psxRegs.GPR.n.lo = (u32)(res & 0xffffffff);
- psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff);
-}
-
-/*********************************************************
-* Register branch logic *
-* Format: OP rs, offset *
-*********************************************************/
-#define RepZBranchi32(op) if(_i32(_rRs_) op 0) doBranch(_BranchTarget_);
-#define RepZBranchLinki32(op) if(_i32(_rRs_) op 0) { _SetLink(31); doBranch(_BranchTarget_); }
-
-void psxBGEZ() { RepZBranchi32(>=) } // Branch if Rs >= 0
-void psxBGEZAL() { RepZBranchLinki32(>=) } // Branch if Rs >= 0 and link
-void psxBGTZ() { RepZBranchi32(>) } // Branch if Rs > 0
-void psxBLEZ() { RepZBranchi32(<=) } // Branch if Rs <= 0
-void psxBLTZ() { RepZBranchi32(<) } // Branch if Rs < 0
-void psxBLTZAL() { RepZBranchLinki32(<) } // Branch if Rs < 0 and link
-
-/*********************************************************
-* Shift arithmetic with constant shift *
-* Format: OP rd, rt, sa *
-*********************************************************/
-void psxSLL() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) << _Sa_; } // Rd = Rt << sa
-void psxSRA() { if (!_Rd_) return; _i32(_rRd_) = _i32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (arithmetic)
-void psxSRL() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (logical)
-
-/*********************************************************
-* Shift arithmetic with variant register shift *
-* Format: OP rd, rt, rs *
-*********************************************************/
-void psxSLLV() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) << _u32(_rRs_); } // Rd = Rt << rs
-void psxSRAV() { if (!_Rd_) return; _i32(_rRd_) = _i32(_rRt_) >> _u32(_rRs_); } // Rd = Rt >> rs (arithmetic)
-void psxSRLV() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) >> _u32(_rRs_); } // Rd = Rt >> rs (logical)
-
-/*********************************************************
-* Load higher 16 bits of the first word in GPR with imm *
-* Format: OP rt, immediate *
-*********************************************************/
-void psxLUI() { if (!_Rt_) return; _u32(_rRt_) = psxRegs.code << 16; } // Upper halfword of Rt = Im
-
-/*********************************************************
-* Move from HI/LO to GPR *
-* Format: OP rd *
-*********************************************************/
-void psxMFHI() { if (!_Rd_) return; _rRd_ = _rHi_; } // Rd = Hi
-void psxMFLO() { if (!_Rd_) return; _rRd_ = _rLo_; } // Rd = Lo
-
-/*********************************************************
-* Move to GPR to HI/LO & Register jump *
-* Format: OP rs *
-*********************************************************/
-void psxMTHI() { _rHi_ = _rRs_; } // Hi = Rs
-void psxMTLO() { _rLo_ = _rRs_; } // Lo = Rs
-
-/*********************************************************
-* Special purpose instructions *
-* Format: OP *
-*********************************************************/
-void psxBREAK() {
- // Break exception - psx rom doens't handles this
-}
-
-void psxSYSCALL() {
- psxRegs.pc -= 4;
- psxException(0x20, branch);
-}
-
-void psxRFE() {
-// SysPrintf("psxRFE\n");
- psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status & 0xfffffff0) |
- ((psxRegs.CP0.n.Status & 0x3c) >> 2);
-}
-
-/*********************************************************
-* Register branch logic *
-* Format: OP rs, rt, offset *
-*********************************************************/
-#define RepBranchi32(op) if(_i32(_rRs_) op _i32(_rRt_)) doBranch(_BranchTarget_);
-
-void psxBEQ() { RepBranchi32(==) } // Branch if Rs == Rt
-void psxBNE() { RepBranchi32(!=) } // Branch if Rs != Rt
-
-/*********************************************************
-* Jump to target *
-* Format: OP target *
-*********************************************************/
-void psxJ() { doBranch(_JumpTarget_); }
-void psxJAL() { _SetLink(31); doBranch(_JumpTarget_); }
-
-/*********************************************************
-* Register jump *
-* Format: OP rs, rd *
-*********************************************************/
-void psxJR() {
- doBranch(_u32(_rRs_));
- psxJumpTest();
-}
-
-void psxJALR() {
- u32 temp = _u32(_rRs_);
- if (_Rd_) { _SetLink(_Rd_); }
- doBranch(temp);
-}
-
-/*********************************************************
-* Load and store for GPR *
-* Format: OP rt, offset(base) *
-*********************************************************/
-
-#define _oB_ (_u32(_rRs_) + _Imm_)
-
-void psxLB() {
- // load delay = 1 latency
- if( branch == 0 )
- {
- // simulate: beq r0,r0,lw+4 / lw / (delay slot)
- psxRegs.pc -= 4;
- doBranch( psxRegs.pc + 4 );
-
- return;
- }
-
-
-
- if (_Rt_) {
- _i32(_rRt_) = (signed char)psxMemRead8(_oB_);
- } else {
- psxMemRead8(_oB_);
- }
-}
-
-void psxLBU() {
- // load delay = 1 latency
- if( branch == 0 )
- {
- // simulate: beq r0,r0,lw+4 / lw / (delay slot)
- psxRegs.pc -= 4;
- doBranch( psxRegs.pc + 4 );
-
- return;
- }
-
-
-
- if (_Rt_) {
- _u32(_rRt_) = psxMemRead8(_oB_);
- } else {
- psxMemRead8(_oB_);
- }
-}
-
-void psxLH() {
- // load delay = 1 latency
- if( branch == 0 )
- {
- // simulate: beq r0,r0,lw+4 / lw / (delay slot)
- psxRegs.pc -= 4;
- doBranch( psxRegs.pc + 4 );
-
- return;
- }
-
-
-
- if (_Rt_) {
- _i32(_rRt_) = (short)psxMemRead16(_oB_);
- } else {
- psxMemRead16(_oB_);
- }
-}
-
-void psxLHU() {
- // load delay = 1 latency
- if( branch == 0 )
- {
- // simulate: beq r0,r0,lw+4 / lw / (delay slot)
- psxRegs.pc -= 4;
- doBranch( psxRegs.pc + 4 );
-
- return;
- }
-
-
-
- if (_Rt_) {
- _u32(_rRt_) = psxMemRead16(_oB_);
- } else {
- psxMemRead16(_oB_);
- }
-}
-
-void psxLW() {
- // load delay = 1 latency
- if( branch == 0 )
- {
- // simulate: beq r0,r0,lw+4 / lw / (delay slot)
- psxRegs.pc -= 4;
- doBranch( psxRegs.pc + 4 );
-
- return;
- }
-
-
-
- if (_Rt_) {
- _u32(_rRt_) = psxMemRead32(_oB_);
- } else {
- psxMemRead32(_oB_);
- }
-}
-
-u32 LWL_MASK[4] = { 0xffffff, 0xffff, 0xff, 0 };
-u32 LWL_SHIFT[4] = { 24, 16, 8, 0 };
-
-void psxLWL() {
- u32 addr = _oB_;
- u32 shift = addr & 3;
- u32 mem = psxMemRead32(addr & ~3);
-
-
- // load delay = 1 latency
- if( branch == 0 )
- {
- // simulate: beq r0,r0,lw+4 / lw / (delay slot)
- psxRegs.pc -= 4;
- doBranch( psxRegs.pc + 4 );
-
- return;
- }
-
-
- if (!_Rt_) return;
- _u32(_rRt_) = ( _u32(_rRt_) & LWL_MASK[shift]) |
- ( mem << LWL_SHIFT[shift]);
-
- /*
- Mem = 1234. Reg = abcd
-
- 0 4bcd (mem << 24) | (reg & 0x00ffffff)
- 1 34cd (mem << 16) | (reg & 0x0000ffff)
- 2 234d (mem << 8) | (reg & 0x000000ff)
- 3 1234 (mem ) | (reg & 0x00000000)
- */
-}
-
-u32 LWR_MASK[4] = { 0, 0xff000000, 0xffff0000, 0xffffff00 };
-u32 LWR_SHIFT[4] = { 0, 8, 16, 24 };
-
-void psxLWR() {
- u32 addr = _oB_;
- u32 shift = addr & 3;
- u32 mem = psxMemRead32(addr & ~3);
-
-
-
- // load delay = 1 latency
- if( branch == 0 )
- {
- // simulate: beq r0,r0,lw+4 / lw / (delay slot)
- psxRegs.pc -= 4;
- doBranch( psxRegs.pc + 4 );
-
- return;
- }
-
-
-
- if (!_Rt_) return;
- _u32(_rRt_) = ( _u32(_rRt_) & LWR_MASK[shift]) |
- ( mem >> LWR_SHIFT[shift]);
-
- /*
- Mem = 1234. Reg = abcd
-
- 0 1234 (mem ) | (reg & 0x00000000)
- 1 a123 (mem >> 8) | (reg & 0xff000000)
- 2 ab12 (mem >> 16) | (reg & 0xffff0000)
- 3 abc1 (mem >> 24) | (reg & 0xffffff00)
- */
-}
-
-void psxSB() { psxMemWrite8 (_oB_, _u8 (_rRt_)); }
-void psxSH() { psxMemWrite16(_oB_, _u16(_rRt_)); }
-void psxSW() { psxMemWrite32(_oB_, _u32(_rRt_)); }
-
-u32 SWL_MASK[4] = { 0xffffff00, 0xffff0000, 0xff000000, 0 };
-u32 SWL_SHIFT[4] = { 24, 16, 8, 0 };
-
-void psxSWL() {
- u32 addr = _oB_;
- u32 shift = addr & 3;
- u32 mem = psxMemRead32(addr & ~3);
-
- psxMemWrite32(addr & ~3, (_u32(_rRt_) >> SWL_SHIFT[shift]) |
- ( mem & SWL_MASK[shift]) );
- /*
- Mem = 1234. Reg = abcd
-
- 0 123a (reg >> 24) | (mem & 0xffffff00)
- 1 12ab (reg >> 16) | (mem & 0xffff0000)
- 2 1abc (reg >> 8) | (mem & 0xff000000)
- 3 abcd (reg ) | (mem & 0x00000000)
- */
-}
-
-u32 SWR_MASK[4] = { 0, 0xff, 0xffff, 0xffffff };
-u32 SWR_SHIFT[4] = { 0, 8, 16, 24 };
-
-void psxSWR() {
- u32 addr = _oB_;
- u32 shift = addr & 3;
- u32 mem = psxMemRead32(addr & ~3);
-
- psxMemWrite32(addr & ~3, (_u32(_rRt_) << SWR_SHIFT[shift]) |
- ( mem & SWR_MASK[shift]) );
-
- /*
- Mem = 1234. Reg = abcd
-
- 0 abcd (reg ) | (mem & 0x00000000)
- 1 bcd4 (reg << 8) | (mem & 0x000000ff)
- 2 cd34 (reg << 16) | (mem & 0x0000ffff)
- 3 d234 (reg << 24) | (mem & 0x00ffffff)
- */
-}
-
-/*********************************************************
-* Moves between GPR and COPx *
-* Format: OP rt, fs *
-*********************************************************/
-void psxMFC0()
-{
- // load delay = 1 latency
- if( branch == 0 )
- {
- // simulate: beq r0,r0,lw+4 / lw / (delay slot)
- psxRegs.pc -= 4;
- doBranch( psxRegs.pc + 4 );
-
- return;
- }
-
-
- if (!_Rt_) return;
-
- _i32(_rRt_) = (int)_rFs_;
-}
-
-void psxCFC0()
-{
- // load delay = 1 latency
- if( branch == 0 )
- {
- // simulate: beq r0,r0,lw+4 / lw / (delay slot)
- psxRegs.pc -= 4;
- doBranch( psxRegs.pc + 4 );
-
- return;
- }
-
-
- if (!_Rt_) return;
-
- _i32(_rRt_) = (int)_rFs_;
-}
-
-void psxTestSWInts() {
- // the next code is untested, if u know please
- // tell me if it works ok or not (linuzappz)
- if (psxRegs.CP0.n.Cause & psxRegs.CP0.n.Status & 0x0300 &&
- psxRegs.CP0.n.Status & 0x1) {
- psxException(psxRegs.CP0.n.Cause, branch);
- }
-}
-
-static __inline void MTC0(int reg, u32 val) {
-// SysPrintf("MTC0 %d: %x\n", reg, val);
- switch (reg) {
- case 12: // Status
- psxRegs.CP0.r[12] = val;
- psxTestSWInts();
- break;
-
- case 13: // Cause
- psxRegs.CP0.n.Cause = val & ~(0xfc00);
- psxTestSWInts();
- break;
-
- default:
- psxRegs.CP0.r[reg] = val;
- break;
- }
-}
-
-void psxMTC0() { MTC0(_Rd_, _u32(_rRt_)); }
-void psxCTC0() { MTC0(_Rd_, _u32(_rRt_)); }
-
-
-
-void psxMFC2()
-{
- // load delay = 1 latency
- if( branch == 0 )
- {
- // simulate: beq r0,r0,lw+4 / lw / (delay slot)
- psxRegs.pc -= 4;
- doBranch( psxRegs.pc + 4 );
-
- return;
- }
-
- gteMFC2();
-}
-
-
-void psxCFC2()
-{
- // load delay = 1 latency
- if( branch == 0 )
- {
- // simulate: beq r0,r0,lw+4 / lw / (delay slot)
- psxRegs.pc -= 4;
- doBranch( psxRegs.pc + 4 );
-
- return;
- }
-
- gteCFC2();
-}
-
-
-/*********************************************************
-* Unknow instruction (would generate an exception) *
-* Format: ? *
-*********************************************************/
-void psxNULL() {
-#ifdef PSXCPU_LOG
- PSXCPU_LOG("psx: Unimplemented op %x\n", psxRegs.code);
-#endif
-}
-
-void psxSPECIAL() {
- psxSPC[_Funct_]();
-}
-
-void psxREGIMM() {
- psxREG[_Rt_]();
-}
-
-void psxCOP0() {
- psxCP0[_Rs_]();
-}
-
-void psxCOP2() {
- if ((psxRegs.CP0.n.Status & 0x40000000) == 0 )
- return;
-
- psxCP2[_Funct_]();
-}
-
-void psxBASIC() {
- psxCP2BSC[_Rs_]();
-}
-
-void psxHLE() {
-// psxHLEt[psxRegs.code & 0xffff]();
- psxHLEt[psxRegs.code & 0x07](); // HDHOSHY experimental patch
-}
-
-void (*psxBSC[64])() = {
- psxSPECIAL, psxREGIMM, psxJ , psxJAL , psxBEQ , psxBNE , psxBLEZ, psxBGTZ,
- psxADDI , psxADDIU , psxSLTI, psxSLTIU, psxANDI, psxORI , psxXORI, psxLUI ,
- psxCOP0 , psxNULL , psxCOP2, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL,
- psxNULL , psxNULL , psxNULL, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL,
- psxLB , psxLH , psxLWL , psxLW , psxLBU , psxLHU , psxLWR , psxNULL,
- psxSB , psxSH , psxSWL , psxSW , psxNULL, psxNULL, psxSWR , psxNULL,
- psxNULL , psxNULL , gteLWC2, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL,
- psxNULL , psxNULL , gteSWC2, psxHLE , psxNULL, psxNULL, psxNULL, psxNULL
-};
-
-
-void (*psxSPC[64])() = {
- psxSLL , psxNULL , psxSRL , psxSRA , psxSLLV , psxNULL , psxSRLV, psxSRAV,
- psxJR , psxJALR , psxNULL, psxNULL, psxSYSCALL, psxBREAK, psxNULL, psxNULL,
- psxMFHI, psxMTHI , psxMFLO, psxMTLO, psxNULL , psxNULL , psxNULL, psxNULL,
- psxMULT, psxMULTU, psxDIV , psxDIVU, psxNULL , psxNULL , psxNULL, psxNULL,
- psxADD , psxADDU , psxSUB , psxSUBU, psxAND , psxOR , psxXOR , psxNOR ,
- psxNULL, psxNULL , psxSLT , psxSLTU, psxNULL , psxNULL , psxNULL, psxNULL,
- psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL,
- psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL
-};
-
-void (*psxREG[32])() = {
- psxBLTZ , psxBGEZ , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
- psxNULL , psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
- psxBLTZAL, psxBGEZAL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
- psxNULL , psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL
-};
-
-void (*psxCP0[32])() = {
- psxMFC0, psxNULL, psxCFC0, psxNULL, psxMTC0, psxNULL, psxCTC0, psxNULL,
- psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
- psxRFE , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
- psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL
-};
-
-void (*psxCP2[64])() = {
- psxBASIC, gteRTPS , psxNULL , psxNULL, psxNULL, psxNULL , gteNCLIP, psxNULL, // 00
- psxNULL , psxNULL , psxNULL , psxNULL, gteOP , psxNULL , psxNULL , psxNULL, // 08
- gteDPCS , gteINTPL, gteMVMVA, gteNCDS, gteCDP , psxNULL , gteNCDT , psxNULL, // 10
- psxNULL , psxNULL , psxNULL , gteNCCS, gteCC , psxNULL , gteNCS , psxNULL, // 18
- gteNCT , psxNULL , psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, // 20
- gteSQR , gteDCPL , gteDPCT , psxNULL, psxNULL, gteAVSZ3, gteAVSZ4, psxNULL, // 28
- gteRTPT , psxNULL , psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, // 30
- psxNULL , psxNULL , psxNULL , psxNULL, psxNULL, gteGPF , gteGPL , gteNCCT // 38
-};
-
-void (*psxCP2BSC[32])() = {
- psxMFC2, psxNULL, psxCFC2, psxNULL, gteMTC2, psxNULL, gteCTC2, psxNULL,
- psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
- psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
- psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL
-};
-
-
-///////////////////////////////////////////
-
-static int intInit() {
- return 0;
-}
-
-static void intReset() {
- psxRegs.ICache_valid = FALSE;
-}
-
-static void intExecute() {
- for (;;)
- execI();
-}
-
-static void intExecuteBlock() {
- branch2 = 0;
- while (!branch2) execI();
-}
-
-static void intClear(u32 Addr, u32 Size) {
-}
-
-static void intShutdown() {
-}
-
-// interpreter execution
-static inline void execI() {
- u32 *code = Read_ICache(psxRegs.pc, FALSE);
- psxRegs.code = ((code == NULL) ? 0 : SWAP32(*code));
-
- debugI();
-
- if (Config.Debug) ProcessDebug();
-
- psxRegs.pc += 4;
- psxRegs.cycle += BIAS;
-
- psxBSC[psxRegs.code >> 26]();
-}
-
-R3000Acpu psxInt = {
- intInit,
- intReset,
- intExecute,
- intExecuteBlock,
- intClear,
- intShutdown
-};
+/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +/* + * PSX assembly interpreter. + */ + +#include "psxcommon.h" +#include "r3000a.h" +#include "gte.h" +#include "psxhle.h" + +static int branch = 0; +static int branch2 = 0; +static u32 branchPC; + +// These macros are used to assemble the repassembler functions + +#ifdef PSXCPU_LOG +#define debugI() PSXCPU_LOG("%s\n", disR3000AF(psxRegs.code, psxRegs.pc)); +#else +#define debugI() +#endif + +static inline void execI(); + +// Subsets +void (*psxBSC[64])(); +void (*psxSPC[64])(); +void (*psxREG[32])(); +void (*psxCP0[32])(); +void (*psxCP2[64])(); +void (*psxCP2BSC[32])(); + +static void delayRead(int reg, u32 bpc) { + u32 rold, rnew; + +// SysPrintf("delayRead at %x!\n", psxRegs.pc); + + rold = psxRegs.GPR.r[reg]; + psxBSC[psxRegs.code >> 26](); // branch delay load + rnew = psxRegs.GPR.r[reg]; + + psxRegs.pc = bpc; + + branch = 0; + + psxRegs.GPR.r[reg] = rold; + execI(); // first branch opcode + psxRegs.GPR.r[reg] = rnew; + + psxBranchTest(); +} + +static void delayWrite(int reg, u32 bpc) { + +/* SysPrintf("delayWrite at %x!\n", psxRegs.pc); + + SysPrintf("%s\n", disR3000AF(psxRegs.code, psxRegs.pc-4)); + SysPrintf("%s\n", disR3000AF(PSXMu32(bpc), bpc));*/ + + // no changes from normal behavior + + psxBSC[psxRegs.code >> 26](); + + branch = 0; + psxRegs.pc = bpc; + + psxBranchTest(); +} + +static void delayReadWrite(int reg, u32 bpc) { + +// SysPrintf("delayReadWrite at %x!\n", psxRegs.pc); + + // the branch delay load is skipped + + branch = 0; + psxRegs.pc = bpc; + + psxBranchTest(); +} + +// this defines shall be used with the tmp +// of the next func (instead of _Funct_...) +#define _tFunct_ ((tmp ) & 0x3F) // The funct part of the instruction register +#define _tRd_ ((tmp >> 11) & 0x1F) // The rd part of the instruction register +#define _tRt_ ((tmp >> 16) & 0x1F) // The rt part of the instruction register +#define _tRs_ ((tmp >> 21) & 0x1F) // The rs part of the instruction register +#define _tSa_ ((tmp >> 6) & 0x1F) // The sa part of the instruction register + +int psxTestLoadDelay(int reg, u32 tmp) { + if (tmp == 0) return 0; // NOP + switch (tmp >> 26) { + case 0x00: // SPECIAL + switch (_tFunct_) { + case 0x00: // SLL + case 0x02: case 0x03: // SRL/SRA + if (_tRd_ == reg && _tRt_ == reg) return 1; else + if (_tRt_ == reg) return 2; else + if (_tRd_ == reg) return 3; + break; + + case 0x08: // JR + if (_tRs_ == reg) return 2; + break; + case 0x09: // JALR + if (_tRd_ == reg && _tRs_ == reg) return 1; else + if (_tRs_ == reg) return 2; else + if (_tRd_ == reg) return 3; + break; + + // SYSCALL/BREAK just a break; + + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x24: case 0x25: case 0x26: case 0x27: + case 0x2a: case 0x2b: // ADD/ADDU... + case 0x04: case 0x06: case 0x07: // SLLV... + if (_tRd_ == reg && (_tRt_ == reg || _tRs_ == reg)) return 1; else + if (_tRt_ == reg || _tRs_ == reg) return 2; else + if (_tRd_ == reg) return 3; + break; + + case 0x10: case 0x12: // MFHI/MFLO + if (_tRd_ == reg) return 3; + break; + case 0x11: case 0x13: // MTHI/MTLO + if (_tRs_ == reg) return 2; + break; + + case 0x18: case 0x19: + case 0x1a: case 0x1b: // MULT/DIV... + if (_tRt_ == reg || _tRs_ == reg) return 2; + break; + } + break; + + case 0x01: // REGIMM + switch (_tRt_) { + case 0x00: case 0x01: + case 0x10: case 0x11: // BLTZ/BGEZ... + // Xenogears - lbu v0 / beq v0 + // - no load delay (fixes battle loading) + break; + + if (_tRs_ == reg) return 2; + break; + } + break; + + // J would be just a break; + case 0x03: // JAL + if (31 == reg) return 3; + break; + + case 0x04: case 0x05: // BEQ/BNE + // Xenogears - lbu v0 / beq v0 + // - no load delay (fixes battle loading) + break; + + if (_tRs_ == reg || _tRt_ == reg) return 2; + break; + + case 0x06: case 0x07: // BLEZ/BGTZ + // Xenogears - lbu v0 / beq v0 + // - no load delay (fixes battle loading) + break; + + if (_tRs_ == reg) return 2; + break; + + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: // ADDI/ADDIU... + if (_tRt_ == reg && _tRs_ == reg) return 1; else + if (_tRs_ == reg) return 2; else + if (_tRt_ == reg) return 3; + break; + + case 0x0f: // LUI + if (_tRt_ == reg) return 3; + break; + + case 0x10: // COP0 + switch (_tFunct_) { + case 0x00: // MFC0 + if (_tRt_ == reg) return 3; + break; + case 0x02: // CFC0 + if (_tRt_ == reg) return 3; + break; + case 0x04: // MTC0 + if (_tRt_ == reg) return 2; + break; + case 0x06: // CTC0 + if (_tRt_ == reg) return 2; + break; + // RFE just a break; + } + break; + + case 0x12: // COP2 + switch (_tFunct_) { + case 0x00: + switch (_tRs_) { + case 0x00: // MFC2 + if (_tRt_ == reg) return 3; + break; + case 0x02: // CFC2 + if (_tRt_ == reg) return 3; + break; + case 0x04: // MTC2 + if (_tRt_ == reg) return 2; + break; + case 0x06: // CTC2 + if (_tRt_ == reg) return 2; + break; + } + break; + // RTPS... break; + } + break; + + case 0x22: case 0x26: // LWL/LWR + if (_tRt_ == reg) return 3; else + if (_tRs_ == reg) return 2; + break; + + case 0x20: case 0x21: case 0x23: + case 0x24: case 0x25: // LB/LH/LW/LBU/LHU + if (_tRt_ == reg && _tRs_ == reg) return 1; else + if (_tRs_ == reg) return 2; else + if (_tRt_ == reg) return 3; + break; + + case 0x28: case 0x29: case 0x2a: + case 0x2b: case 0x2e: // SB/SH/SWL/SW/SWR + if (_tRt_ == reg || _tRs_ == reg) return 2; + break; + + case 0x32: case 0x3a: // LWC2/SWC2 + if (_tRs_ == reg) return 2; + break; + } + + return 0; +} + +void psxDelayTest(int reg, u32 bpc) { + u32 *code; + u32 tmp; + + // Don't execute yet - just peek + code = Read_ICache(bpc, TRUE); + + tmp = ((code == NULL) ? 0 : SWAP32(*code)); + branch = 1; + + switch (psxTestLoadDelay(reg, tmp)) { + case 1: + delayReadWrite(reg, bpc); return; + case 2: + delayRead(reg, bpc); return; + case 3: + delayWrite(reg, bpc); return; + } + psxBSC[psxRegs.code >> 26](); + + branch = 0; + psxRegs.pc = bpc; + + psxBranchTest(); +} + +static u32 psxBranchNoDelay(void) { + u32 *code; + u32 temp; + + code = Read_ICache(psxRegs.pc, TRUE); + psxRegs.code = ((code == NULL) ? 0 : SWAP32(*code)); + switch (_Op_) { + case 0x00: // SPECIAL + switch (_Funct_) { + case 0x08: // JR + return _u32(_rRs_); + case 0x09: // JALR + temp = _u32(_rRs_); + if (_Rd_) { _SetLink(_Rd_); } + return temp; + } + break; + case 0x01: // REGIMM + switch (_Rt_) { + case 0x00: // BLTZ + if (_i32(_rRs_) < 0) + return _BranchTarget_; + break; + case 0x01: // BGEZ + if (_i32(_rRs_) >= 0) + return _BranchTarget_; + break; + case 0x08: // BLTZAL + if (_i32(_rRs_) < 0) { + _SetLink(31); + return _BranchTarget_; + } + break; + case 0x09: // BGEZAL + if (_i32(_rRs_) >= 0) { + _SetLink(31); + return _BranchTarget_; + } + break; + } + break; + case 0x02: // J + return _JumpTarget_; + case 0x03: // JAL + _SetLink(31); + return _JumpTarget_; + case 0x04: // BEQ + if (_i32(_rRs_) == _i32(_rRt_)) + return _BranchTarget_; + break; + case 0x05: // BNE + if (_i32(_rRs_) != _i32(_rRt_)) + return _BranchTarget_; + break; + case 0x06: // BLEZ + if (_i32(_rRs_) <= 0) + return _BranchTarget_; + break; + case 0x07: // BGTZ + if (_i32(_rRs_) > 0) + return _BranchTarget_; + break; + } + + return (u32)-1; +} + +static int psxDelayBranchExec(u32 tar) { + execI(); + + branch = 0; + psxRegs.pc = tar; + psxRegs.cycle += BIAS; + psxBranchTest(); + return 1; +} + +static int psxDelayBranchTest(u32 tar1) { + u32 tar2, tmp1, tmp2; + + tar2 = psxBranchNoDelay(); + if (tar2 == (u32)-1) + return 0; + + debugI(); + + /* + * Branch in delay slot: + * - execute 1 instruction at tar1 + * - jump to tar2 (target of branch in delay slot; this branch + * has no normal delay slot, instruction at tar1 was fetched instead) + */ + psxRegs.pc = tar1; + tmp1 = psxBranchNoDelay(); + if (tmp1 == (u32)-1) { + return psxDelayBranchExec(tar2); + } + debugI(); + psxRegs.cycle += BIAS; + + /* + * Got a branch at tar1: + * - execute 1 instruction at tar2 + * - jump to target of that branch (tmp1) + */ + psxRegs.pc = tar2; + tmp2 = psxBranchNoDelay(); + if (tmp2 == (u32)-1) { + return psxDelayBranchExec(tmp1); + } + debugI(); + psxRegs.cycle += BIAS; + + /* + * Got a branch at tar2: + * - execute 1 instruction at tmp1 + * - jump to target of that branch (tmp2) + */ + psxRegs.pc = tmp1; + return psxDelayBranchExec(tmp2); +} + +static __inline void doBranch(u32 tar) { + u32 *code; + u32 tmp; + + branch2 = branch = 1; + branchPC = tar; + + // notaz: check for branch in delay slot + if (psxDelayBranchTest(tar)) + return; + + // branch delay slot + code = Read_ICache(psxRegs.pc, TRUE); + + psxRegs.code = ((code == NULL) ? 0 : SWAP32(*code)); + + debugI(); + + psxRegs.pc += 4; + psxRegs.cycle += BIAS; + + // check for load delay + tmp = psxRegs.code >> 26; + switch (tmp) { + case 0x10: // COP0 + switch (_Rs_) { + case 0x00: // MFC0 + case 0x02: // CFC0 + psxDelayTest(_Rt_, branchPC); + return; + } + break; + case 0x12: // COP2 + switch (_Funct_) { + case 0x00: + switch (_Rs_) { + case 0x00: // MFC2 + case 0x02: // CFC2 + psxDelayTest(_Rt_, branchPC); + return; + } + break; + } + break; + case 0x32: // LWC2 + psxDelayTest(_Rt_, branchPC); + return; + default: + if (tmp >= 0x20 && tmp <= 0x26) { // LB/LH/LWL/LW/LBU/LHU/LWR + psxDelayTest(_Rt_, branchPC); + return; + } + break; + } + + psxBSC[psxRegs.code >> 26](); + + branch = 0; + psxRegs.pc = branchPC; + + psxBranchTest(); +} + +/********************************************************* +* Arithmetic with immediate operand * +* Format: OP rt, rs, immediate * +*********************************************************/ +void psxADDI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im (Exception on Integer Overflow) +void psxADDIU() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im +void psxANDI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) & _ImmU_; } // Rt = Rs And Im +void psxORI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) | _ImmU_; } // Rt = Rs Or Im +void psxXORI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) ^ _ImmU_; } // Rt = Rs Xor Im +void psxSLTI() { if (!_Rt_) return; _rRt_ = _i32(_rRs_) < _Imm_ ; } // Rt = Rs < Im (Signed) +void psxSLTIU() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) < ((u32)_Imm_); } // Rt = Rs < Im (Unsigned) + +/********************************************************* +* Register arithmetic * +* Format: OP rd, rs, rt * +*********************************************************/ +void psxADD() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt (Exception on Integer Overflow) +void psxADDU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt +void psxSUB() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt (Exception on Integer Overflow) +void psxSUBU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt +void psxAND() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) & _u32(_rRt_); } // Rd = Rs And Rt +void psxOR() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) | _u32(_rRt_); } // Rd = Rs Or Rt +void psxXOR() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) ^ _u32(_rRt_); } // Rd = Rs Xor Rt +void psxNOR() { if (!_Rd_) return; _rRd_ =~(_u32(_rRs_) | _u32(_rRt_)); }// Rd = Rs Nor Rt +void psxSLT() { if (!_Rd_) return; _rRd_ = _i32(_rRs_) < _i32(_rRt_); } // Rd = Rs < Rt (Signed) +void psxSLTU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) < _u32(_rRt_); } // Rd = Rs < Rt (Unsigned) + +/********************************************************* +* Register mult/div & Register trap logic * +* Format: OP rs, rt * +*********************************************************/ +void psxDIV() { + if (_i32(_rRt_) != 0) { + _i32(_rLo_) = _i32(_rRs_) / _i32(_rRt_); + _i32(_rHi_) = _i32(_rRs_) % _i32(_rRt_); + } + else { + _i32(_rLo_) = 0xffffffff; + _i32(_rHi_) = _i32(_rRs_); + } +} + +void psxDIVU() { + if (_rRt_ != 0) { + _rLo_ = _rRs_ / _rRt_; + _rHi_ = _rRs_ % _rRt_; + } + else { + _rLo_ = 0xffffffff; + _rHi_ = _rRs_; + } +} + +void psxMULT() { + u64 res = (s64)((s64)_i32(_rRs_) * (s64)_i32(_rRt_)); + + psxRegs.GPR.n.lo = (u32)(res & 0xffffffff); + psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff); +} + +void psxMULTU() { + u64 res = (u64)((u64)_u32(_rRs_) * (u64)_u32(_rRt_)); + + psxRegs.GPR.n.lo = (u32)(res & 0xffffffff); + psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff); +} + +/********************************************************* +* Register branch logic * +* Format: OP rs, offset * +*********************************************************/ +#define RepZBranchi32(op) if(_i32(_rRs_) op 0) doBranch(_BranchTarget_); +#define RepZBranchLinki32(op) if(_i32(_rRs_) op 0) { _SetLink(31); doBranch(_BranchTarget_); } + +void psxBGEZ() { RepZBranchi32(>=) } // Branch if Rs >= 0 +void psxBGEZAL() { RepZBranchLinki32(>=) } // Branch if Rs >= 0 and link +void psxBGTZ() { RepZBranchi32(>) } // Branch if Rs > 0 +void psxBLEZ() { RepZBranchi32(<=) } // Branch if Rs <= 0 +void psxBLTZ() { RepZBranchi32(<) } // Branch if Rs < 0 +void psxBLTZAL() { RepZBranchLinki32(<) } // Branch if Rs < 0 and link + +/********************************************************* +* Shift arithmetic with constant shift * +* Format: OP rd, rt, sa * +*********************************************************/ +void psxSLL() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) << _Sa_; } // Rd = Rt << sa +void psxSRA() { if (!_Rd_) return; _i32(_rRd_) = _i32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (arithmetic) +void psxSRL() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (logical) + +/********************************************************* +* Shift arithmetic with variant register shift * +* Format: OP rd, rt, rs * +*********************************************************/ +void psxSLLV() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) << _u32(_rRs_); } // Rd = Rt << rs +void psxSRAV() { if (!_Rd_) return; _i32(_rRd_) = _i32(_rRt_) >> _u32(_rRs_); } // Rd = Rt >> rs (arithmetic) +void psxSRLV() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) >> _u32(_rRs_); } // Rd = Rt >> rs (logical) + +/********************************************************* +* Load higher 16 bits of the first word in GPR with imm * +* Format: OP rt, immediate * +*********************************************************/ +void psxLUI() { if (!_Rt_) return; _u32(_rRt_) = psxRegs.code << 16; } // Upper halfword of Rt = Im + +/********************************************************* +* Move from HI/LO to GPR * +* Format: OP rd * +*********************************************************/ +void psxMFHI() { if (!_Rd_) return; _rRd_ = _rHi_; } // Rd = Hi +void psxMFLO() { if (!_Rd_) return; _rRd_ = _rLo_; } // Rd = Lo + +/********************************************************* +* Move to GPR to HI/LO & Register jump * +* Format: OP rs * +*********************************************************/ +void psxMTHI() { _rHi_ = _rRs_; } // Hi = Rs +void psxMTLO() { _rLo_ = _rRs_; } // Lo = Rs + +/********************************************************* +* Special purpose instructions * +* Format: OP * +*********************************************************/ +void psxBREAK() { + // Break exception - psx rom doens't handles this +} + +void psxSYSCALL() { + psxRegs.pc -= 4; + psxException(0x20, branch); +} + +void psxRFE() { +// SysPrintf("psxRFE\n"); + psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status & 0xfffffff0) | + ((psxRegs.CP0.n.Status & 0x3c) >> 2); +} + +/********************************************************* +* Register branch logic * +* Format: OP rs, rt, offset * +*********************************************************/ +#define RepBranchi32(op) if(_i32(_rRs_) op _i32(_rRt_)) doBranch(_BranchTarget_); + +void psxBEQ() { RepBranchi32(==) } // Branch if Rs == Rt +void psxBNE() { RepBranchi32(!=) } // Branch if Rs != Rt + +/********************************************************* +* Jump to target * +* Format: OP target * +*********************************************************/ +void psxJ() { doBranch(_JumpTarget_); } +void psxJAL() { _SetLink(31); doBranch(_JumpTarget_); } + +/********************************************************* +* Register jump * +* Format: OP rs, rd * +*********************************************************/ +void psxJR() { + doBranch(_u32(_rRs_)); + psxJumpTest(); +} + +void psxJALR() { + u32 temp = _u32(_rRs_); + if (_Rd_) { _SetLink(_Rd_); } + doBranch(temp); +} + +/********************************************************* +* Load and store for GPR * +* Format: OP rt, offset(base) * +*********************************************************/ + +#define _oB_ (_u32(_rRs_) + _Imm_) + +void psxLB() { + // load delay = 1 latency + if( branch == 0 ) + { + // simulate: beq r0,r0,lw+4 / lw / (delay slot) + psxRegs.pc -= 4; + doBranch( psxRegs.pc + 4 ); + + return; + } + + + + if (_Rt_) { + _i32(_rRt_) = (signed char)psxMemRead8(_oB_); + } else { + psxMemRead8(_oB_); + } +} + +void psxLBU() { + // load delay = 1 latency + if( branch == 0 ) + { + // simulate: beq r0,r0,lw+4 / lw / (delay slot) + psxRegs.pc -= 4; + doBranch( psxRegs.pc + 4 ); + + return; + } + + + + if (_Rt_) { + _u32(_rRt_) = psxMemRead8(_oB_); + } else { + psxMemRead8(_oB_); + } +} + +void psxLH() { + // load delay = 1 latency + if( branch == 0 ) + { + // simulate: beq r0,r0,lw+4 / lw / (delay slot) + psxRegs.pc -= 4; + doBranch( psxRegs.pc + 4 ); + + return; + } + + + + if (_Rt_) { + _i32(_rRt_) = (short)psxMemRead16(_oB_); + } else { + psxMemRead16(_oB_); + } +} + +void psxLHU() { + // load delay = 1 latency + if( branch == 0 ) + { + // simulate: beq r0,r0,lw+4 / lw / (delay slot) + psxRegs.pc -= 4; + doBranch( psxRegs.pc + 4 ); + + return; + } + + + + if (_Rt_) { + _u32(_rRt_) = psxMemRead16(_oB_); + } else { + psxMemRead16(_oB_); + } +} + +void psxLW() { + // load delay = 1 latency + if( branch == 0 ) + { + // simulate: beq r0,r0,lw+4 / lw / (delay slot) + psxRegs.pc -= 4; + doBranch( psxRegs.pc + 4 ); + + return; + } + + + + if (_Rt_) { + _u32(_rRt_) = psxMemRead32(_oB_); + } else { + psxMemRead32(_oB_); + } +} + +u32 LWL_MASK[4] = { 0xffffff, 0xffff, 0xff, 0 }; +u32 LWL_SHIFT[4] = { 24, 16, 8, 0 }; + +void psxLWL() { + u32 addr = _oB_; + u32 shift = addr & 3; + u32 mem = psxMemRead32(addr & ~3); + + + // load delay = 1 latency + if( branch == 0 ) + { + // simulate: beq r0,r0,lw+4 / lw / (delay slot) + psxRegs.pc -= 4; + doBranch( psxRegs.pc + 4 ); + + return; + } + + + if (!_Rt_) return; + _u32(_rRt_) = ( _u32(_rRt_) & LWL_MASK[shift]) | + ( mem << LWL_SHIFT[shift]); + + /* + Mem = 1234. Reg = abcd + + 0 4bcd (mem << 24) | (reg & 0x00ffffff) + 1 34cd (mem << 16) | (reg & 0x0000ffff) + 2 234d (mem << 8) | (reg & 0x000000ff) + 3 1234 (mem ) | (reg & 0x00000000) + */ +} + +u32 LWR_MASK[4] = { 0, 0xff000000, 0xffff0000, 0xffffff00 }; +u32 LWR_SHIFT[4] = { 0, 8, 16, 24 }; + +void psxLWR() { + u32 addr = _oB_; + u32 shift = addr & 3; + u32 mem = psxMemRead32(addr & ~3); + + + + // load delay = 1 latency + if( branch == 0 ) + { + // simulate: beq r0,r0,lw+4 / lw / (delay slot) + psxRegs.pc -= 4; + doBranch( psxRegs.pc + 4 ); + + return; + } + + + + if (!_Rt_) return; + _u32(_rRt_) = ( _u32(_rRt_) & LWR_MASK[shift]) | + ( mem >> LWR_SHIFT[shift]); + + /* + Mem = 1234. Reg = abcd + + 0 1234 (mem ) | (reg & 0x00000000) + 1 a123 (mem >> 8) | (reg & 0xff000000) + 2 ab12 (mem >> 16) | (reg & 0xffff0000) + 3 abc1 (mem >> 24) | (reg & 0xffffff00) + */ +} + +void psxSB() { psxMemWrite8 (_oB_, _u8 (_rRt_)); } +void psxSH() { psxMemWrite16(_oB_, _u16(_rRt_)); } +void psxSW() { psxMemWrite32(_oB_, _u32(_rRt_)); } + +u32 SWL_MASK[4] = { 0xffffff00, 0xffff0000, 0xff000000, 0 }; +u32 SWL_SHIFT[4] = { 24, 16, 8, 0 }; + +void psxSWL() { + u32 addr = _oB_; + u32 shift = addr & 3; + u32 mem = psxMemRead32(addr & ~3); + + psxMemWrite32(addr & ~3, (_u32(_rRt_) >> SWL_SHIFT[shift]) | + ( mem & SWL_MASK[shift]) ); + /* + Mem = 1234. Reg = abcd + + 0 123a (reg >> 24) | (mem & 0xffffff00) + 1 12ab (reg >> 16) | (mem & 0xffff0000) + 2 1abc (reg >> 8) | (mem & 0xff000000) + 3 abcd (reg ) | (mem & 0x00000000) + */ +} + +u32 SWR_MASK[4] = { 0, 0xff, 0xffff, 0xffffff }; +u32 SWR_SHIFT[4] = { 0, 8, 16, 24 }; + +void psxSWR() { + u32 addr = _oB_; + u32 shift = addr & 3; + u32 mem = psxMemRead32(addr & ~3); + + psxMemWrite32(addr & ~3, (_u32(_rRt_) << SWR_SHIFT[shift]) | + ( mem & SWR_MASK[shift]) ); + + /* + Mem = 1234. Reg = abcd + + 0 abcd (reg ) | (mem & 0x00000000) + 1 bcd4 (reg << 8) | (mem & 0x000000ff) + 2 cd34 (reg << 16) | (mem & 0x0000ffff) + 3 d234 (reg << 24) | (mem & 0x00ffffff) + */ +} + +/********************************************************* +* Moves between GPR and COPx * +* Format: OP rt, fs * +*********************************************************/ +void psxMFC0() +{ + // load delay = 1 latency + if( branch == 0 ) + { + // simulate: beq r0,r0,lw+4 / lw / (delay slot) + psxRegs.pc -= 4; + doBranch( psxRegs.pc + 4 ); + + return; + } + + + if (!_Rt_) return; + + _i32(_rRt_) = (int)_rFs_; +} + +void psxCFC0() +{ + // load delay = 1 latency + if( branch == 0 ) + { + // simulate: beq r0,r0,lw+4 / lw / (delay slot) + psxRegs.pc -= 4; + doBranch( psxRegs.pc + 4 ); + + return; + } + + + if (!_Rt_) return; + + _i32(_rRt_) = (int)_rFs_; +} + +void psxTestSWInts() { + // the next code is untested, if u know please + // tell me if it works ok or not (linuzappz) + if (psxRegs.CP0.n.Cause & psxRegs.CP0.n.Status & 0x0300 && + psxRegs.CP0.n.Status & 0x1) { + psxException(psxRegs.CP0.n.Cause, branch); + } +} + +static __inline void MTC0(int reg, u32 val) { +// SysPrintf("MTC0 %d: %x\n", reg, val); + switch (reg) { + case 12: // Status + psxRegs.CP0.r[12] = val; + psxTestSWInts(); + break; + + case 13: // Cause + psxRegs.CP0.n.Cause = val & ~(0xfc00); + psxTestSWInts(); + break; + + default: + psxRegs.CP0.r[reg] = val; + break; + } +} + +void psxMTC0() { MTC0(_Rd_, _u32(_rRt_)); } +void psxCTC0() { MTC0(_Rd_, _u32(_rRt_)); } + + + +void psxMFC2() +{ + // load delay = 1 latency + if( branch == 0 ) + { + // simulate: beq r0,r0,lw+4 / lw / (delay slot) + psxRegs.pc -= 4; + doBranch( psxRegs.pc + 4 ); + + return; + } + + gteMFC2(); +} + + +void psxCFC2() +{ + // load delay = 1 latency + if( branch == 0 ) + { + // simulate: beq r0,r0,lw+4 / lw / (delay slot) + psxRegs.pc -= 4; + doBranch( psxRegs.pc + 4 ); + + return; + } + + gteCFC2(); +} + + +/********************************************************* +* Unknow instruction (would generate an exception) * +* Format: ? * +*********************************************************/ +void psxNULL() { +#ifdef PSXCPU_LOG + PSXCPU_LOG("psx: Unimplemented op %x\n", psxRegs.code); +#endif +} + +void psxSPECIAL() { + psxSPC[_Funct_](); +} + +void psxREGIMM() { + psxREG[_Rt_](); +} + +void psxCOP0() { + psxCP0[_Rs_](); +} + +void psxCOP2() { + if ((psxRegs.CP0.n.Status & 0x40000000) == 0 ) + return; + + psxCP2[_Funct_](); +} + +void psxBASIC() { + psxCP2BSC[_Rs_](); +} + +void psxHLE() { +// psxHLEt[psxRegs.code & 0xffff](); + psxHLEt[psxRegs.code & 0x07](); // HDHOSHY experimental patch +} + +void (*psxBSC[64])() = { + psxSPECIAL, psxREGIMM, psxJ , psxJAL , psxBEQ , psxBNE , psxBLEZ, psxBGTZ, + psxADDI , psxADDIU , psxSLTI, psxSLTIU, psxANDI, psxORI , psxXORI, psxLUI , + psxCOP0 , psxNULL , psxCOP2, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL , psxNULL , psxNULL, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, + psxLB , psxLH , psxLWL , psxLW , psxLBU , psxLHU , psxLWR , psxNULL, + psxSB , psxSH , psxSWL , psxSW , psxNULL, psxNULL, psxSWR , psxNULL, + psxNULL , psxNULL , gteLWC2, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL , psxNULL , gteSWC2, psxHLE , psxNULL, psxNULL, psxNULL, psxNULL +}; + + +void (*psxSPC[64])() = { + psxSLL , psxNULL , psxSRL , psxSRA , psxSLLV , psxNULL , psxSRLV, psxSRAV, + psxJR , psxJALR , psxNULL, psxNULL, psxSYSCALL, psxBREAK, psxNULL, psxNULL, + psxMFHI, psxMTHI , psxMFLO, psxMTLO, psxNULL , psxNULL , psxNULL, psxNULL, + psxMULT, psxMULTU, psxDIV , psxDIVU, psxNULL , psxNULL , psxNULL, psxNULL, + psxADD , psxADDU , psxSUB , psxSUBU, psxAND , psxOR , psxXOR , psxNOR , + psxNULL, psxNULL , psxSLT , psxSLTU, psxNULL , psxNULL , psxNULL, psxNULL, + psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL, + psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL +}; + +void (*psxREG[32])() = { + psxBLTZ , psxBGEZ , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL , psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxBLTZAL, psxBGEZAL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL , psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL +}; + +void (*psxCP0[32])() = { + psxMFC0, psxNULL, psxCFC0, psxNULL, psxMTC0, psxNULL, psxCTC0, psxNULL, + psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxRFE , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL +}; + +void (*psxCP2[64])() = { + psxBASIC, gteRTPS , psxNULL , psxNULL, psxNULL, psxNULL , gteNCLIP, psxNULL, // 00 + psxNULL , psxNULL , psxNULL , psxNULL, gteOP , psxNULL , psxNULL , psxNULL, // 08 + gteDPCS , gteINTPL, gteMVMVA, gteNCDS, gteCDP , psxNULL , gteNCDT , psxNULL, // 10 + psxNULL , psxNULL , psxNULL , gteNCCS, gteCC , psxNULL , gteNCS , psxNULL, // 18 + gteNCT , psxNULL , psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, // 20 + gteSQR , gteDCPL , gteDPCT , psxNULL, psxNULL, gteAVSZ3, gteAVSZ4, psxNULL, // 28 + gteRTPT , psxNULL , psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, // 30 + psxNULL , psxNULL , psxNULL , psxNULL, psxNULL, gteGPF , gteGPL , gteNCCT // 38 +}; + +void (*psxCP2BSC[32])() = { + psxMFC2, psxNULL, psxCFC2, psxNULL, gteMTC2, psxNULL, gteCTC2, psxNULL, + psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL +}; + + +/////////////////////////////////////////// + +static int intInit() { + return 0; +} + +static void intReset() { + psxRegs.ICache_valid = FALSE; +} + +static void intExecute() { + for (;;) + execI(); +} + +static void intExecuteBlock() { + branch2 = 0; + while (!branch2) execI(); +} + +static void intClear(u32 Addr, u32 Size) { +} + +static void intShutdown() { +} + +// interpreter execution +static inline void execI() { + u32 *code = Read_ICache(psxRegs.pc, FALSE); + psxRegs.code = ((code == NULL) ? 0 : SWAP32(*code)); + + debugI(); + + if (Config.Debug) ProcessDebug(); + + psxRegs.pc += 4; + psxRegs.cycle += BIAS; + + psxBSC[psxRegs.code >> 26](); +} + +R3000Acpu psxInt = { + intInit, + intReset, + intExecute, + intExecuteBlock, + intClear, + intShutdown +}; |
