#include "gte.h"
#include "psxhle.h"
#include "psxinterpreter.h"
+#include <stddef.h>
#include <assert.h>
//#include "debug.h"
#define ProcessDebug()
#define debugI()
#endif
+#ifdef __i386__
+#define INT_ATTR __attribute__((regparm(2)))
+#else
+#define INT_ATTR
+#endif
+#ifndef INVALID_PTR
+#define INVALID_PTR NULL
+#endif
+
// Subsets
-void (*psxBSC[64])();
-void (*psxSPC[64])();
-void (*psxREG[32])();
-void (*psxCP0[32])();
-void (*psxCP2[64])(struct psxCP2Regs *regs);
-void (*psxCP2BSC[32])();
-
-static u32 fetchNoCache(u32 pc)
+static void (INT_ATTR *psxBSC[64])(psxRegisters *regs_, u32 code);
+static void (INT_ATTR *psxSPC[64])(psxRegisters *regs_, u32 code);
+
+static u32 INT_ATTR fetchNoCache(u8 **memRLUT, u32 pc)
{
- u32 *code = (u32 *)PSXM(pc);
- return ((code == NULL) ? 0 : SWAP32(*code));
+ u8 *base = memRLUT[pc >> 16];
+ if (base == INVALID_PTR)
+ return 0;
+ u32 *code = (u32 *)(base + (pc & 0xfffc));
+ return SWAP32(*code);
}
/*
u32 data[4];
} ICache[256];
-static u32 fetchICache(u32 pc)
+static u32 INT_ATTR fetchICache(u8 **memRLUT, u32 pc)
{
// cached?
if (pc < 0xa0000000)
if (((entry->tag ^ pc) & 0xfffffff0) != 0 || pc < entry->tag)
{
- u32 *code = (u32 *)PSXM(pc & ~0x0f);
- if (!code)
+ const u8 *base = memRLUT[pc >> 16];
+ const u32 *code;
+ if (base == INVALID_PTR)
return 0;
+ code = (u32 *)(base + (pc & 0xfff0));
entry->tag = pc;
// treat as 4 words, although other configurations are said to be possible
return entry->data[(pc & 0x0f) >> 2];
}
- return fetchNoCache(pc);
+ return fetchNoCache(memRLUT, pc);
}
-u32 (*fetch)(u32 pc) = fetchNoCache;
+static u32 (INT_ATTR *fetch)(u8 **memRLUT, u32 pc) = fetchNoCache;
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
+ psxBSC[psxRegs.code >> 26](&psxRegs, psxRegs.code); // branch delay load
rnew = psxRegs.GPR.r[reg];
psxRegs.pc = bpc;
// no changes from normal behavior
- psxBSC[psxRegs.code >> 26]();
+ psxBSC[psxRegs.code >> 26](&psxRegs, psxRegs.code);
branch = 0;
psxRegs.pc = bpc;
psxBranchTest();
}
+/**** R3000A Instruction Macros ****/
+#define _PC_ regs_->pc // The next PC to be executed
+
+#define _fOp_(code) ((code >> 26) ) // The opcode part of the instruction register
+#define _fFunct_(code) ((code ) & 0x3F) // The funct part of the instruction register
+#define _fRd_(code) ((code >> 11) & 0x1F) // The rd part of the instruction register
+#define _fRt_(code) ((code >> 16) & 0x1F) // The rt part of the instruction register
+#define _fRs_(code) ((code >> 21) & 0x1F) // The rs part of the instruction register
+#define _fSa_(code) ((code >> 6) & 0x1F) // The sa part of the instruction register
+#define _fIm_(code) ((u16)code) // The immediate part of the instruction register
+#define _fTarget_(code) (code & 0x03ffffff) // The target part of the instruction register
+
+#define _fImm_(code) ((s16)code) // sign-extended immediate
+#define _fImmU_(code) (code&0xffff) // zero-extended immediate
+
+#define _Op_ _fOp_(code)
+#define _Funct_ _fFunct_(code)
+#define _Rd_ _fRd_(code)
+#define _Rt_ _fRt_(code)
+#define _Rs_ _fRs_(code)
+#define _Sa_ _fSa_(code)
+#define _Im_ _fIm_(code)
+#define _Target_ _fTarget_(code)
+
+#define _Imm_ _fImm_(code)
+#define _ImmU_ _fImmU_(code)
+
+#define _rRs_ regs_->GPR.r[_Rs_] // Rs register
+#define _rRt_ regs_->GPR.r[_Rt_] // Rt register
+#define _rRd_ regs_->GPR.r[_Rd_] // Rd register
+#define _rSa_ regs_->GPR.r[_Sa_] // Sa register
+#define _rFs_ regs_->CP0.r[_Rd_] // Fs register
+
+#define _rHi_ regs_->GPR.n.hi // The HI register
+#define _rLo_ regs_->GPR.n.lo // The LO register
+
+#define _JumpTarget_ ((_Target_ * 4) + (_PC_ & 0xf0000000)) // Calculates the target during a jump instruction
+#define _BranchTarget_ ((s16)_Im_ * 4 + _PC_) // Calculates the target during a branch instruction
+
+#define _SetLink(x) regs_->GPR.r[x] = _PC_ + 4; // Sets the return address in the link register
+
+#define OP(name) \
+ static inline INT_ATTR void name(psxRegisters *regs_, u32 code)
+
// 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 _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) {
+#define _i32(x) (s32)(x)
+#define _u32(x) (u32)(x)
+
+static int psxTestLoadDelay(int reg, u32 tmp) {
if (tmp == 0) return 0; // NOP
switch (tmp >> 26) {
case 0x00: // SPECIAL
return 0;
}
-void psxDelayTest(int reg, u32 bpc) {
- u32 tmp = fetch(bpc);
+static void psxDelayTest(int reg, u32 bpc) {
+ u32 tmp = fetch(psxMemRLUT, bpc);
branch = 1;
switch (psxTestLoadDelay(reg, tmp)) {
case 3:
delayWrite(reg, bpc); return;
}
- psxBSC[psxRegs.code >> 26]();
+ psxBSC[psxRegs.code >> 26](&psxRegs, psxRegs.code);
branch = 0;
psxRegs.pc = bpc;
psxBranchTest();
}
-static u32 psxBranchNoDelay(void) {
- u32 temp;
+static u32 psxBranchNoDelay(psxRegisters *regs_) {
+ u32 temp, code;
- psxRegs.code = fetch(psxRegs.pc);
+ regs_->code = code = fetch(psxMemRLUT, regs_->pc);
switch (_Op_) {
case 0x00: // SPECIAL
switch (_Funct_) {
static int psxDelayBranchTest(u32 tar1) {
u32 tar2, tmp1, tmp2;
- tar2 = psxBranchNoDelay();
+ tar2 = psxBranchNoDelay(&psxRegs);
if (tar2 == (u32)-1)
return 0;
* has no normal delay slot, instruction at tar1 was fetched instead)
*/
psxRegs.pc = tar1;
- tmp1 = psxBranchNoDelay();
+ tmp1 = psxBranchNoDelay(&psxRegs);
if (tmp1 == (u32)-1) {
return psxDelayBranchExec(tar2);
}
* - jump to target of that branch (tmp1)
*/
psxRegs.pc = tar2;
- tmp2 = psxBranchNoDelay();
+ tmp2 = psxBranchNoDelay(&psxRegs);
if (tmp2 == (u32)-1) {
return psxDelayBranchExec(tmp1);
}
}
static void doBranch(u32 tar) {
- u32 tmp;
+ u32 tmp, code;
branch2 = branch = 1;
branchPC = tar;
if (psxDelayBranchTest(tar))
return;
- psxRegs.code = fetch(psxRegs.pc);
+ psxRegs.code = code = fetch(psxMemRLUT, psxRegs.pc);
debugI();
break;
}
- psxBSC[psxRegs.code >> 26]();
+ psxBSC[psxRegs.code >> 26](&psxRegs, psxRegs.code);
branch = 0;
psxRegs.pc = branchPC;
* 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)
+OP(psxADDI) { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im (Exception on Integer Overflow)
+OP(psxADDIU) { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im
+OP(psxANDI) { if (!_Rt_) return; _rRt_ = _u32(_rRs_) & _ImmU_; } // Rt = Rs And Im
+OP(psxORI) { if (!_Rt_) return; _rRt_ = _u32(_rRs_) | _ImmU_; } // Rt = Rs Or Im
+OP(psxXORI) { if (!_Rt_) return; _rRt_ = _u32(_rRs_) ^ _ImmU_; } // Rt = Rs Xor Im
+OP(psxSLTI) { if (!_Rt_) return; _rRt_ = _i32(_rRs_) < _Imm_ ; } // Rt = Rs < Im (Signed)
+OP(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)
+OP(psxADD) { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt (Exception on Integer Overflow)
+OP(psxADDU) { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt
+OP(psxSUB) { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt (Exception on Integer Overflow)
+OP(psxSUBU) { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt
+OP(psxAND) { if (!_Rd_) return; _rRd_ = _u32(_rRs_) & _u32(_rRt_); } // Rd = Rs And Rt
+OP(psxOR) { if (!_Rd_) return; _rRd_ = _u32(_rRs_) | _u32(_rRt_); } // Rd = Rs Or Rt
+OP(psxXOR) { if (!_Rd_) return; _rRd_ = _u32(_rRs_) ^ _u32(_rRt_); } // Rd = Rs Xor Rt
+OP(psxNOR) { if (!_Rd_) return; _rRd_ =~(_u32(_rRs_) | _u32(_rRt_)); }// Rd = Rs Nor Rt
+OP(psxSLT) { if (!_Rd_) return; _rRd_ = _i32(_rRs_) < _i32(_rRt_); } // Rd = Rs < Rt (Signed)
+OP(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_)) {
- _i32(_rHi_) = _i32(_rRs_);
- if (_i32(_rRs_) & 0x80000000) {
- _i32(_rLo_) = 1;
- } else {
- _i32(_rLo_) = 0xFFFFFFFF;
- }
-/*
- * Notaz said that this was "not needed" for ARM platforms and could slow it down so let's disable for ARM.
- * This fixes a crash issue that can happen when running Amidog's CPU test.
- * (It still stays stuck to a black screen but at least it doesn't crash anymore)
- */
+OP(psxDIV) {
+ if (!_rRt_) {
+ _rHi_ = _rRs_;
+ if (_rRs_ & 0x80000000) {
+ _rLo_ = 1;
+ } else {
+ _rLo_ = 0xFFFFFFFF;
+ }
+ }
#if !defined(__arm__) && !defined(__aarch64__)
- } else if (_i32(_rRs_) == 0x80000000 && _i32(_rRt_) == 0xFFFFFFFF) {
- _i32(_rLo_) = 0x80000000;
- _i32(_rHi_) = 0;
+ else if (_rRs_ == 0x80000000 && _rRt_ == 0xFFFFFFFF) {
+ _rLo_ = 0x80000000;
+ _rHi_ = 0;
+ }
#endif
- } else {
- _i32(_rLo_) = _i32(_rRs_) / _i32(_rRt_);
- _i32(_rHi_) = _i32(_rRs_) % _i32(_rRt_);
- }
+ else {
+ _rLo_ = _i32(_rRs_) / _i32(_rRt_);
+ _rHi_ = _i32(_rRs_) % _i32(_rRt_);
+ }
}
-void psxDIV_stall() {
- psxRegs.muldivBusyCycle = psxRegs.cycle + 37;
- psxDIV();
+OP(psxDIV_stall) {
+ regs_->muldivBusyCycle = regs_->cycle + 37;
+ psxDIV(regs_, code);
}
-void psxDIVU() {
+OP(psxDIVU) {
if (_rRt_ != 0) {
_rLo_ = _rRs_ / _rRt_;
_rHi_ = _rRs_ % _rRt_;
}
else {
- _i32(_rLo_) = 0xffffffff;
- _i32(_rHi_) = _i32(_rRs_);
+ _rLo_ = 0xffffffff;
+ _rHi_ = _rRs_;
}
}
-void psxDIVU_stall() {
- psxRegs.muldivBusyCycle = psxRegs.cycle + 37;
- psxDIVU();
+OP(psxDIVU_stall) {
+ regs_->muldivBusyCycle = regs_->cycle + 37;
+ psxDIVU(regs_, code);
}
-void psxMULT() {
- u64 res = (s64)((s64)_i32(_rRs_) * (s64)_i32(_rRt_));
+OP(psxMULT) {
+ u64 res = (s64)_i32(_rRs_) * _i32(_rRt_);
- psxRegs.GPR.n.lo = (u32)(res & 0xffffffff);
- psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff);
+ regs_->GPR.n.lo = (u32)res;
+ regs_->GPR.n.hi = (u32)(res >> 32);
}
-void psxMULT_stall() {
+OP(psxMULT_stall) {
// approximate, but maybe good enough
u32 rs = _rRs_;
u32 lz = __builtin_clz(((rs ^ ((s32)rs >> 21)) | 1));
u32 c = 7 + (2 - (lz / 11)) * 4;
- psxRegs.muldivBusyCycle = psxRegs.cycle + c;
- psxMULT();
+ regs_->muldivBusyCycle = regs_->cycle + c;
+ psxMULT(regs_, code);
}
-void psxMULTU() {
- u64 res = (u64)((u64)_u32(_rRs_) * (u64)_u32(_rRt_));
+OP(psxMULTU) {
+ u64 res = (u64)_u32(_rRs_) * _u32(_rRt_);
- psxRegs.GPR.n.lo = (u32)(res & 0xffffffff);
- psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff);
+ regs_->GPR.n.lo = (u32)(res & 0xffffffff);
+ regs_->GPR.n.hi = (u32)((res >> 32) & 0xffffffff);
}
-void psxMULTU_stall() {
+OP(psxMULTU_stall) {
// approximate, but maybe good enough
u32 lz = __builtin_clz(_rRs_ | 1);
u32 c = 7 + (2 - (lz / 11)) * 4;
- psxRegs.muldivBusyCycle = psxRegs.cycle + c;
- psxMULTU();
+ regs_->muldivBusyCycle = regs_->cycle + c;
+ psxMULTU(regs_, code);
}
/*********************************************************
#define RepZBranchi32(op) if(_i32(_rRs_) op 0) doBranch(_BranchTarget_);
#define RepZBranchLinki32(op) { _SetLink(31); if(_i32(_rRs_) op 0) { 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
+OP(psxBGEZ) { RepZBranchi32(>=) } // Branch if Rs >= 0
+OP(psxBGEZAL) { RepZBranchLinki32(>=) } // Branch if Rs >= 0 and link
+OP(psxBGTZ) { RepZBranchi32(>) } // Branch if Rs > 0
+OP(psxBLEZ) { RepZBranchi32(<=) } // Branch if Rs <= 0
+OP(psxBLTZ) { RepZBranchi32(<) } // Branch if Rs < 0
+OP(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)
+OP(psxSLL) { if (!_Rd_) return; _rRd_ = _u32(_rRt_) << _Sa_; } // Rd = Rt << sa
+OP(psxSRA) { if (!_Rd_) return; _rRd_ = _i32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (arithmetic)
+OP(psxSRL) { if (!_Rd_) return; _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_) & 0x1F); } // Rd = Rt << rs
-void psxSRAV() { if (!_Rd_) return; _i32(_rRd_) = _i32(_rRt_) >> (_u32(_rRs_) & 0x1F); } // Rd = Rt >> rs (arithmetic)
-void psxSRLV() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) >> (_u32(_rRs_) & 0x1F); } // Rd = Rt >> rs (logical)
+OP(psxSLLV) { if (!_Rd_) return; _rRd_ = _u32(_rRt_) << (_u32(_rRs_) & 0x1F); } // Rd = Rt << rs
+OP(psxSRAV) { if (!_Rd_) return; _rRd_ = _i32(_rRt_) >> (_u32(_rRs_) & 0x1F); } // Rd = Rt >> rs (arithmetic)
+OP(psxSRLV) { if (!_Rd_) return; _rRd_ = _u32(_rRt_) >> (_u32(_rRs_) & 0x1F); } // 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
+OP(psxLUI) { if (!_Rt_) return; _rRt_ = 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
+OP(psxMFHI) { if (!_Rd_) return; _rRd_ = _rHi_; } // Rd = Hi
+OP(psxMFLO) { if (!_Rd_) return; _rRd_ = _rLo_; } // Rd = Lo
-static void mflohiCheckStall(void)
+static void mflohiCheckStall(psxRegisters *regs_)
{
- u32 left = psxRegs.muldivBusyCycle - psxRegs.cycle;
+ u32 left = regs_->muldivBusyCycle - regs_->cycle;
if (left <= 37) {
//printf("muldiv stall %u\n", left);
- psxRegs.cycle = psxRegs.muldivBusyCycle;
+ regs_->cycle = regs_->muldivBusyCycle;
}
}
-void psxMFHI_stall() { mflohiCheckStall(); psxMFHI(); }
-void psxMFLO_stall() { mflohiCheckStall(); psxMFLO(); }
+OP(psxMFHI_stall) { mflohiCheckStall(regs_); psxMFHI(regs_, code); }
+OP(psxMFLO_stall) { mflohiCheckStall(regs_); psxMFLO(regs_, code); }
/*********************************************************
* Move to GPR to HI/LO & Register jump *
* Format: OP rs *
*********************************************************/
-void psxMTHI() { _rHi_ = _rRs_; } // Hi = Rs
-void psxMTLO() { _rLo_ = _rRs_; } // Lo = Rs
+OP(psxMTHI) { _rHi_ = _rRs_; } // Hi = Rs
+OP(psxMTLO) { _rLo_ = _rRs_; } // Lo = Rs
/*********************************************************
* Special purpose instructions *
* Format: OP *
*********************************************************/
-void psxBREAK() {
- psxRegs.pc -= 4;
+OP(psxBREAK) {
+ regs_->pc -= 4;
psxException(0x24, branch);
}
-void psxSYSCALL() {
- psxRegs.pc -= 4;
+OP(psxSYSCALL) {
+ regs_->pc -= 4;
psxException(0x20, branch);
}
-void psxRFE() {
+static inline void psxTestSWInts(psxRegisters *regs_) {
+ if (regs_->CP0.n.Cause & regs_->CP0.n.Status & 0x0300 &&
+ regs_->CP0.n.Status & 0x1) {
+ regs_->CP0.n.Cause &= ~0x7c;
+ psxException(regs_->CP0.n.Cause, branch);
+ }
+}
+
+OP(psxRFE) {
// SysPrintf("psxRFE\n");
- psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status & 0xfffffff0) |
- ((psxRegs.CP0.n.Status & 0x3c) >> 2);
- psxTestSWInts();
+ regs_->CP0.n.Status = (regs_->CP0.n.Status & 0xfffffff0) |
+ ((regs_->CP0.n.Status & 0x3c) >> 2);
+ psxTestSWInts(regs_);
}
/*********************************************************
*********************************************************/
#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
+OP(psxBEQ) { RepBranchi32(==) } // Branch if Rs == Rt
+OP(psxBNE) { RepBranchi32(!=) } // Branch if Rs != Rt
/*********************************************************
* Jump to target *
* Format: OP target *
*********************************************************/
-void psxJ() { doBranch(_JumpTarget_); }
-void psxJAL() { _SetLink(31); doBranch(_JumpTarget_); }
+OP(psxJ) { doBranch(_JumpTarget_); }
+OP(psxJAL) { _SetLink(31); doBranch(_JumpTarget_); }
/*********************************************************
* Register jump *
* Format: OP rs, rd *
*********************************************************/
-void psxJR() {
+OP(psxJR) {
doBranch(_rRs_ & ~3);
psxJumpTest();
}
-void psxJALR() {
+OP(psxJALR) {
u32 temp = _u32(_rRs_);
if (_Rd_) { _SetLink(_Rd_); }
doBranch(temp & ~3);
* Format: OP rt, offset(base) *
*********************************************************/
-#define _oB_ (_u32(_rRs_) + _Imm_)
-
-void psxLB() {
- if (_Rt_) {
- _i32(_rRt_) = (signed 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_);
- }
-}
+#define _oB_ (regs_->GPR.r[_Rs_] + _Imm_)
-void psxLW() {
- 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 };
+OP(psxLB) { u32 v = (s8)psxMemRead8(_oB_); if (_Rt_) _rRt_ = v; }
+OP(psxLBU) { u32 v = psxMemRead8(_oB_); if (_Rt_) _rRt_ = v; }
+OP(psxLH) { u32 v = (s16)psxMemRead16(_oB_); if (_Rt_) _rRt_ = v; }
+OP(psxLHU) { u32 v = psxMemRead16(_oB_); if (_Rt_) _rRt_ = v; }
+OP(psxLW) { u32 v = psxMemRead32(_oB_); if (_Rt_) _rRt_ = v; }
-void psxLWL() {
+OP(psxLWL) {
+ static const u32 LWL_MASK[4] = { 0xffffff, 0xffff, 0xff, 0 };
+ static const u32 LWL_SHIFT[4] = { 24, 16, 8, 0 };
u32 addr = _oB_;
u32 shift = addr & 3;
u32 mem = psxMemRead32(addr & ~3);
if (!_Rt_) return;
- _u32(_rRt_) = ( _u32(_rRt_) & LWL_MASK[shift]) |
- ( mem << LWL_SHIFT[shift]);
+ _rRt_ = (_u32(_rRt_) & LWL_MASK[shift]) | (mem << LWL_SHIFT[shift]);
/*
Mem = 1234. Reg = abcd
*/
}
-u32 LWR_MASK[4] = { 0, 0xff000000, 0xffff0000, 0xffffff00 };
-u32 LWR_SHIFT[4] = { 0, 8, 16, 24 };
-
-void psxLWR() {
+OP(psxLWR) {
+ static const u32 LWR_MASK[4] = { 0, 0xff000000, 0xffff0000, 0xffffff00 };
+ static const u32 LWR_SHIFT[4] = { 0, 8, 16, 24 };
u32 addr = _oB_;
u32 shift = addr & 3;
u32 mem = psxMemRead32(addr & ~3);
if (!_Rt_) return;
- _u32(_rRt_) = ( _u32(_rRt_) & LWR_MASK[shift]) |
- ( mem >> LWR_SHIFT[shift]);
+ _rRt_ = (_u32(_rRt_) & LWR_MASK[shift]) | (mem >> LWR_SHIFT[shift]);
/*
Mem = 1234. Reg = abcd
*/
}
-void psxSB() { psxMemWrite8 (_oB_, _rRt_ & 0xff); }
-void psxSH() { psxMemWrite16(_oB_, _rRt_ & 0xffff); }
-void psxSW() { psxMemWrite32(_oB_, _rRt_); }
-
-u32 SWL_MASK[4] = { 0xffffff00, 0xffff0000, 0xff000000, 0 };
-u32 SWL_SHIFT[4] = { 24, 16, 8, 0 };
+OP(psxSB) { psxMemWrite8 (_oB_, _rRt_ & 0xff); }
+OP(psxSH) { psxMemWrite16(_oB_, _rRt_ & 0xffff); }
+OP(psxSW) { psxMemWrite32(_oB_, _rRt_); }
-void psxSWL() {
+OP(psxSWL) {
+ static const u32 SWL_MASK[4] = { 0xffffff00, 0xffff0000, 0xff000000, 0 };
+ static const u32 SWL_SHIFT[4] = { 24, 16, 8, 0 };
u32 addr = _oB_;
u32 shift = addr & 3;
u32 mem = psxMemRead32(addr & ~3);
*/
}
-u32 SWR_MASK[4] = { 0, 0xff, 0xffff, 0xffffff };
-u32 SWR_SHIFT[4] = { 0, 8, 16, 24 };
-
-void psxSWR() {
+OP(psxSWR) {
+ static const u32 SWR_MASK[4] = { 0, 0xff, 0xffff, 0xffffff };
+ static const u32 SWR_SHIFT[4] = { 0, 8, 16, 24 };
u32 addr = _oB_;
u32 shift = addr & 3;
u32 mem = psxMemRead32(addr & ~3);
* 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 psxTestSWInts() {
- if (psxRegs.CP0.n.Cause & psxRegs.CP0.n.Status & 0x0300 &&
- psxRegs.CP0.n.Status & 0x1) {
- psxRegs.CP0.n.Cause &= ~0x7c;
- psxException(psxRegs.CP0.n.Cause, branch);
- }
-}
+OP(psxMFC0) { if (!_Rt_) return; _rRt_ = _rFs_; }
+OP(psxCFC0) { if (!_Rt_) return; _rRt_ = _rFs_; }
-void MTC0(int reg, u32 val) {
+void MTC0(psxRegisters *regs_, int reg, u32 val) {
// SysPrintf("MTC0 %d: %x\n", reg, val);
switch (reg) {
case 12: // Status
- psxRegs.CP0.r[12] = val;
- psxTestSWInts();
+ regs_->CP0.r[12] = val;
+ psxTestSWInts(regs_);
break;
case 13: // Cause
- psxRegs.CP0.n.Cause &= ~0x0300;
- psxRegs.CP0.n.Cause |= val & 0x0300;
- psxTestSWInts();
+ regs_->CP0.n.Cause &= ~0x0300;
+ regs_->CP0.n.Cause |= val & 0x0300;
+ psxTestSWInts(regs_);
break;
default:
- psxRegs.CP0.r[reg] = val;
+ regs_->CP0.r[reg] = val;
break;
}
}
-void psxMTC0() { MTC0(_Rd_, _u32(_rRt_)); }
-void psxCTC0() { MTC0(_Rd_, _u32(_rRt_)); }
+OP(psxMTC0) { MTC0(regs_, _Rd_, _u32(_rRt_)); }
+OP(psxCTC0) { MTC0(regs_, _Rd_, _u32(_rRt_)); }
/*********************************************************
* Unknow instruction (would generate an exception) *
* Format: ? *
*********************************************************/
-void psxNULL() {
+static inline void psxNULL_(void) {
#ifdef PSXCPU_LOG
PSXCPU_LOG("psx: Unimplemented op %x\n", psxRegs.code);
#endif
}
-void psxSPECIAL() {
- psxSPC[_Funct_]();
-}
+OP(psxNULL) { psxNULL_(); }
+void gteNULL(struct psxCP2Regs *regs) { psxNULL_(); }
-void psxREGIMM() {
- psxREG[_Rt_]();
+OP(psxSPECIAL) {
+ psxSPC[_Funct_](regs_, code);
}
-void psxCOP0() {
- psxCP0[_Rs_]();
+OP(psxCOP0) {
+ switch (_Rs_) {
+ case 0x00: psxMFC0(regs_, code); break;
+ case 0x02: psxCFC0(regs_, code); break;
+ case 0x04: psxMTC0(regs_, code); break;
+ case 0x06: psxCTC0(regs_, code); break;
+ case 0x10: psxRFE(regs_, code); break;
+ default: psxNULL_(); break;
+ }
}
-void psxCOP2() {
- psxCP2[_Funct_]((struct psxCP2Regs *)&psxRegs.CP2D);
+OP(psxCOP2) {
+ psxCP2[_Funct_](®s_->CP2);
}
-void psxCOP2_stall() {
+OP(psxCOP2_stall) {
u32 f = _Funct_;
gteCheckStall(f);
- psxCP2[f]((struct psxCP2Regs *)&psxRegs.CP2D);
+ psxCP2[f](®s_->CP2);
+}
+
+OP(gteMFC2) {
+ if (!_Rt_) return;
+ regs_->GPR.r[_Rt_] = MFC2(®s_->CP2, _Rd_);
+}
+
+OP(gteCFC2) {
+ if (!_Rt_) return;
+ regs_->GPR.r[_Rt_] = regs_->CP2C.r[_Rd_];
+}
+
+OP(gteMTC2) {
+ MTC2(®s_->CP2, regs_->GPR.r[_Rt_], _Rd_);
+}
+
+OP(gteCTC2) {
+ CTC2(®s_->CP2, regs_->GPR.r[_Rt_], _Rd_);
+}
+
+OP(gteLWC2) {
+ MTC2(®s_->CP2, psxMemRead32(_oB_), _Rt_);
+}
+
+OP(gteSWC2) {
+ psxMemWrite32(_oB_, MFC2(®s_->CP2, _Rt_));
+}
+
+OP(gteLWC2_stall) {
+ gteCheckStall(0);
+ gteLWC2(regs_, code);
}
-void psxBASIC(struct psxCP2Regs *regs) {
- psxCP2BSC[_Rs_]();
+OP(gteSWC2_stall) {
+ gteCheckStall(0);
+ gteSWC2(regs_, code);
+}
+
+static void psxBASIC(struct psxCP2Regs *cp2regs) {
+ psxRegisters *regs_ = (void *)((char *)cp2regs - offsetof(psxRegisters, CP2));
+ u32 code = regs_->code;
+ assert(regs_ == &psxRegs);
+ switch (_Rs_) {
+ case 0x00: gteMFC2(regs_, code); break;
+ case 0x02: gteCFC2(regs_, code); break;
+ case 0x04: gteMTC2(regs_, code); break;
+ case 0x06: gteCTC2(regs_, code); break;
+ default: psxNULL_(); break;
+ }
+}
+
+OP(psxREGIMM) {
+ switch (_Rt_) {
+ case 0x00: psxBLTZ(regs_, code); break;
+ case 0x01: psxBGEZ(regs_, code); break;
+ case 0x10: psxBLTZAL(regs_, code); break;
+ case 0x11: psxBGEZAL(regs_, code); break;
+ default: psxNULL_(); break;
+ }
}
-void psxHLE() {
-// psxHLEt[psxRegs.code & 0xffff]();
-// psxHLEt[psxRegs.code & 0x07](); // HDHOSHY experimental patch
- uint32_t hleCode = psxRegs.code & 0x03ffffff;
+OP(psxHLE) {
+ uint32_t hleCode = code & 0x03ffffff;
if (hleCode >= (sizeof(psxHLEt) / sizeof(psxHLEt[0]))) {
- psxNULL();
+ psxNULL_();
} else {
psxHLEt[hleCode]();
}
}
-void (*psxBSC[64])() = {
+static void (INT_ATTR *psxBSC[64])(psxRegisters *regs_, u32 code) = {
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 , gteSWC2, psxHLE , psxNULL, psxNULL, psxNULL, psxNULL
};
-
-void (*psxSPC[64])() = {
+static void (INT_ATTR *psxSPC[64])(psxRegisters *regs_, u32 code) = {
psxSLL , psxNULL , psxSRL , psxSRA , psxSLLV , psxNULL , psxSRLV, psxSRAV,
psxJR , psxJALR , psxNULL, psxNULL, psxSYSCALL, psxBREAK, psxNULL, psxNULL,
psxMFHI, psxMTHI , psxMFLO, psxMTLO, 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])(struct psxCP2Regs *regs) = {
- 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
+ psxBASIC, gteRTPS , gteNULL , gteNULL, gteNULL, gteNULL , gteNCLIP, gteNULL, // 00
+ gteNULL , gteNULL , gteNULL , gteNULL, gteOP , gteNULL , gteNULL , gteNULL, // 08
+ gteDPCS , gteINTPL, gteMVMVA, gteNCDS, gteCDP , gteNULL , gteNCDT , gteNULL, // 10
+ gteNULL , gteNULL , gteNULL , gteNCCS, gteCC , gteNULL , gteNCS , gteNULL, // 18
+ gteNCT , gteNULL , gteNULL , gteNULL, gteNULL, gteNULL , gteNULL , gteNULL, // 20
+ gteSQR , gteDCPL , gteDPCT , gteNULL, gteNULL, gteAVSZ3, gteAVSZ4, gteNULL, // 28
+ gteRTPT , gteNULL , gteNULL , gteNULL, gteNULL, gteNULL , gteNULL , gteNULL, // 30
+ gteNULL , gteNULL , gteNULL , gteNULL, gteNULL, gteGPF , gteGPL , gteNCCT // 38
};
-
///////////////////////////////////////////
static int intInit() {
memset(&ICache, 0xff, sizeof(ICache));
}
-void intExecute() {
+static inline void execI_(u8 **memRLUT, psxRegisters *regs_) {
+ regs_->code = fetch(memRLUT, regs_->pc);
+
+ debugI();
+
+ if (Config.Debug) ProcessDebug();
+
+ regs_->pc += 4;
+ regs_->cycle += BIAS;
+
+ psxBSC[regs_->code >> 26](regs_, regs_->code);
+}
+
+static void intExecute() {
+ psxRegisters *regs_ = &psxRegs;
+ u8 **memRLUT = psxMemRLUT;
extern int stop;
- for (;!stop;)
- execI();
+
+ while (!stop)
+ execI_(memRLUT, regs_);
}
-void intExecuteBlock() {
+static void intExecuteBlock() {
+ psxRegisters *regs_ = &psxRegs;
+ u8 **memRLUT = psxMemRLUT;
+
branch2 = 0;
- while (!branch2) execI();
+ while (!branch2)
+ execI_(memRLUT, regs_);
}
static void intClear(u32 Addr, u32 Size) {
static void intShutdown() {
}
-// interpreter execution
+// single step (may do several ops in case of a branch)
void execI() {
- psxRegs.code = fetch(psxRegs.pc);
-
- debugI();
-
- if (Config.Debug) ProcessDebug();
-
- psxRegs.pc += 4;
- psxRegs.cycle += BIAS;
-
- psxBSC[psxRegs.code >> 26]();
+ execI_(psxMemRLUT, &psxRegs);
}
R3000Acpu psxInt = {