/* Pcsx - Pc Psx Emulator * Copyright (C) 1999-2002 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include "PsxCommon.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() \ if (Config.Log) { \ PSXCPU_LOG("CPU: %s\n", disR3000AF(psxRegs.code, psxRegs.pc)); \ } #else #define debugI() #endif #define execI() { \ psxRegs.code = PSXMu32(psxRegs.pc); \ \ debugI(); \ \ psxRegs.pc+= 4; \ psxRegs.cycle++; \ \ psxBSC[psxRegs.code >> 26](); \ } #define doBranch(tar) { \ branch2 = branch = 1; \ branchPC = tar; \ execI(); \ branch = 0; \ psxRegs.pc = branchPC; \ \ psxBranchTest(); \ } // Subsets void (*psxBSC[64])(); void (*psxSPC[64])(); void (*psxREG[32])(); void (*psxCP0[32])(); void (*psxCP2[64])(); void (*psxCP2BSC[32])(); /********************************************************* * 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_) < _ImmU_; } // 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_); } } void psxDIVU() { if (_rRt_ != 0) { _rLo_ = _rRs_ / _rRt_; _rHi_ = _rRs_ % _rRt_; } } void psxMULT() { u64 res = (s64)((s64)_i32(_rRs_) * (s64)_i32(_rRt_)); psxRegs.GPR.n.lo = (unsigned long)(res & 0xffffffff); psxRegs.GPR.n.hi = (unsigned long)((res >> 32) & 0xffffffff); } void psxMULTU() { u64 res = (u64)((u64)_u32(_rRs_) * (u64)_u32(_rRt_)); psxRegs.GPR.n.lo = (unsigned long)(res & 0xffffffff); psxRegs.GPR.n.hi = (unsigned long)((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() { 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_)); } void psxJALR() { if (_Rd_) { _SetLink(_Rd_); } doBranch(_u32(_rRs_)); } /********************************************************* * Load and store for GPR * * Format: OP rt, offset(base) * *********************************************************/ #define _oB_ (_u32(_rRs_) + _Imm_) void psxLB() { if (_Rt_) { _i32(_rRt_) = (char)psxMemRead8(_oB_); } else { psxMemRead8(_oB_); } } void psxLBU() { if (_Rt_) { _u32(_rRt_) = psxMemRead8(_oB_); } else { psxMemRead8(_oB_); } } void psxLH() { if (_Rt_) { _i32(_rRt_) = (short)psxMemRead16(_oB_); } else { psxMemRead16(_oB_); } } void psxLHU() { if (_Rt_) { _u32(_rRt_) = psxMemRead16(_oB_); } else { psxMemRead16(_oB_); } } void psxLW() { if (_Rt_) { _u32(_rRt_) = psxMemRead32(_oB_); } else { psxMemRead32(_oB_); } } void psxLWL() { u32 shift = (_oB_ & 3) << 3; u32 mem = psxMemRead32(_oB_ & 0xfffffffc); if (!_Rt_) return; _u32(_rRt_) = ( _u32(_rRt_) & (0x00ffffff >> shift) ) | ( mem << (24 - 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) */ } void psxLWR() { u32 shift = (_oB_ & 3) << 3; u32 mem = psxMemRead32(_oB_ & 0xfffffffc); if (!_Rt_) return; _u32(_rRt_) = ( _u32(_rRt_) & (0xffffff00 << (24 - shift)) ) | ( mem >> 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_)); } void psxSWL() { u32 shift = (_oB_ & 3) << 3; u32 mem = psxMemRead32(_oB_ & 0xfffffffc); psxMemWrite32((_oB_ & 0xfffffffc), ( ( _u32(_rRt_) >> (24 - shift) ) ) | ( mem & (0xffffff00 << 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) */ } void psxSWR() { u32 shift = (_oB_ & 3) << 3; u32 mem = psxMemRead32(_oB_ & 0xfffffffc); psxMemWrite32((_oB_ & 0xfffffffc), ( ( _u32(_rRt_) << shift ) | (mem & (0x00ffffff >> (24 - 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() { if (!_Rt_) return; _i32(_rRt_) = (int)_rFs_; } void psxCFC0() { if (!_Rt_) return; _i32(_rRt_) = (int)_rFs_; } void psxMTC0() { _rFs_ = _u32(_rRt_); } void psxCTC0() { _rFs_ = _u32(_rRt_); } /********************************************************* * 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() { psxCP2[_Funct_](); } void psxBASIC() { psxCP2BSC[_Rs_](); } void psxHLE() { psxHLEt[psxRegs.code & 0xff](); } 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])() = { gteMFC2, psxNULL, gteCFC2, 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() { } static void intExecute() { for (;;) execI(); } static void intExecuteBlock() { branch2 = 0; while (!branch2) execI(); } static void intClear(u32 Addr, u32 Size) { } static void intShutdown() { } R3000Acpu psxInt = { intInit, intReset, intExecute, intExecuteBlock, intClear, intShutdown };