1 /***************************************************************************
2 * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team *
3 * Copyright (C) 2023 notaz *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA. *
19 ***************************************************************************/
22 * PSX assembly interpreter.
25 #include "psxcommon.h"
29 #include "psxinterpreter.h"
32 #include "../include/compiler_features.h"
34 // these may cause issues: because of poor timing we may step
35 // on instructions that real hardware would never reach
36 #define DO_EXCEPTION_RESERVEDI
37 #define HANDLE_LOAD_DELAY
39 static int branchSeen = 0;
42 #define INT_ATTR __attribute__((regparm(2)))
47 #define INVALID_PTR NULL
51 static void (INT_ATTR *psxBSC[64])(psxRegisters *regs_, u32 code);
52 static void (INT_ATTR *psxSPC[64])(psxRegisters *regs_, u32 code);
55 static void doLoad(psxRegisters *regs, u32 r, u32 val)
57 #ifdef HANDLE_LOAD_DELAY
58 int sel = regs->dloadSel ^ 1;
59 assert(regs->dloadReg[sel] == 0);
60 regs->dloadReg[sel] = r;
61 regs->dloadVal[sel] = r ? val : 0;
62 if (regs->dloadReg[sel ^ 1] == r)
63 regs->dloadVal[sel ^ 1] = regs->dloadReg[sel ^ 1] = 0;
65 regs->GPR.r[r] = r ? val : 0;
69 static void dloadRt(psxRegisters *regs, u32 r, u32 val)
71 #ifdef HANDLE_LOAD_DELAY
72 int sel = regs->dloadSel;
73 if (unlikely(regs->dloadReg[sel] == r))
74 regs->dloadVal[sel] = regs->dloadReg[sel] = 0;
76 regs->GPR.r[r] = r ? val : 0;
79 static void dloadStep(psxRegisters *regs)
81 #ifdef HANDLE_LOAD_DELAY
82 int sel = regs->dloadSel;
83 regs->GPR.r[regs->dloadReg[sel]] = regs->dloadVal[sel];
84 regs->dloadVal[sel] = regs->dloadReg[sel] = 0;
86 assert(regs->GPR.r[0] == 0);
90 static void dloadFlush(psxRegisters *regs)
92 #ifdef HANDLE_LOAD_DELAY
93 regs->GPR.r[regs->dloadReg[0]] = regs->dloadVal[0];
94 regs->GPR.r[regs->dloadReg[1]] = regs->dloadVal[1];
95 regs->dloadVal[0] = regs->dloadVal[1] = 0;
96 regs->dloadReg[0] = regs->dloadReg[1] = 0;
97 assert(regs->GPR.r[0] == 0);
101 static void dloadClear(psxRegisters *regs)
103 #ifdef HANDLE_LOAD_DELAY
104 regs->dloadVal[0] = regs->dloadVal[1] = 0;
105 regs->dloadReg[0] = regs->dloadReg[1] = 0;
110 static void intException(psxRegisters *regs, u32 pc, u32 cause)
113 //FILE *f = fopen("/tmp/psx_ram.bin", "wb");
114 //fwrite(psxM, 1, 0x200000, f); fclose(f);
115 log_unhandled("exception %08x @%08x ra=%08x\n",
116 cause, pc, regs->GPR.n.ra);
120 psxException(cause, regs->branching, ®s->CP0);
121 regs->branching = R3000A_BRANCH_NONE_OR_EXCEPTION;
124 // exception caused by current instruction (excluding unkasking)
125 static void intExceptionInsn(psxRegisters *regs, u32 cause)
127 cause |= (regs->code & 0x0c000000) << 2;
128 intException(regs, regs->pc - 4, cause);
131 static noinline void intExceptionReservedInsn(psxRegisters *regs)
133 #ifdef DO_EXCEPTION_RESERVEDI
134 static u32 ppc_ = ~0u;
135 if (regs->pc != ppc_) {
136 SysPrintf("reserved instruction %08x @%08x ra=%08x\n",
137 regs->code, regs->pc - 4, regs->GPR.n.ra);
140 intExceptionInsn(regs, R3000E_RI << 2);
144 // 29 Enable for 80000000-ffffffff
145 // 30 Enable for 00000000-7fffffff
146 // 31 Enable exception
147 #define DBR_ABIT(dc, a) ((dc) & (1u << (29+(((a)>>31)^1))))
148 #define DBR_EN_EXEC(dc, a) (((dc) & 0x01800000) == 0x01800000 && DBR_ABIT(dc, a))
149 #define DBR_EN_LD(dc, a) (((dc) & 0x06800000) == 0x06800000 && DBR_ABIT(dc, a))
150 #define DBR_EN_ST(dc, a) (((dc) & 0x0a800000) == 0x0a800000 && DBR_ABIT(dc, a))
151 static void intExceptionDebugBp(psxRegisters *regs, u32 pc)
153 psxCP0Regs *cp0 = ®s->CP0;
155 cp0->n.Cause &= 0x300;
156 cp0->n.Cause |= (regs->branching << 30) | (R3000E_Bp << 2);
157 cp0->n.SR = (cp0->n.SR & ~0x3f) | ((cp0->n.SR & 0x0f) << 2);
158 cp0->n.EPC = regs->branching ? pc - 4 : pc;
159 psxRegs.pc = 0x80000040;
162 static int execBreakCheck(psxRegisters *regs, u32 pc)
164 if (unlikely(DBR_EN_EXEC(regs->CP0.n.DCIC, pc) &&
165 ((pc ^ regs->CP0.n.BPC) & regs->CP0.n.BPCM) == 0))
167 regs->CP0.n.DCIC |= 0x03;
168 if (regs->CP0.n.DCIC & (1u << 31)) {
169 intExceptionDebugBp(regs, pc);
176 // get an opcode without triggering exceptions or affecting cache
177 u32 intFakeFetch(u32 pc)
179 u32 *code = (u32 *)psxm(pc & ~0x3, 0);
180 if (unlikely(code == INVALID_PTR))
182 return SWAP32(*code);
186 static u32 INT_ATTR fetchNoCache(psxRegisters *regs, u8 **memRLUT, u32 pc)
188 u32 *code = (u32 *)psxm_lut(pc & ~0x3, 0, memRLUT);
189 if (unlikely(code == INVALID_PTR)) {
190 SysPrintf("game crash @%08x, ra=%08x\n", pc, regs->GPR.n.ra);
191 intException(regs, pc, R3000E_IBE << 2);
192 return 0; // execute as nop
194 return SWAP32(*code);
199 Use old CPU cache code when the RAM location is updated with new code (affects in-game racing)
201 static struct cache_entry {
206 static u32 INT_ATTR fetchICache(psxRegisters *regs, u8 **memRLUT, u32 pc)
211 // this is not how the hardware works but whatever
212 struct cache_entry *entry = &ICache[(pc & 0xff0) >> 4];
214 if (((entry->tag ^ pc) & 0xfffffff0) != 0 || pc < entry->tag)
216 const u32 *code = (u32 *)psxm_lut(pc & ~0xf, 0, memRLUT);
217 if (unlikely(code == INVALID_PTR)) {
218 SysPrintf("game crash @%08x, ra=%08x\n", pc, regs->GPR.n.ra);
219 intException(regs, pc, R3000E_IBE << 2);
220 return 0; // execute as nop
224 // treat as 4 words, although other configurations are said to be possible
227 case 0x00: entry->data[0] = SWAP32(code[0]);
228 case 0x04: entry->data[1] = SWAP32(code[1]);
229 case 0x08: entry->data[2] = SWAP32(code[2]);
230 case 0x0c: entry->data[3] = SWAP32(code[3]);
233 return entry->data[(pc & 0x0f) >> 2];
236 return fetchNoCache(regs, memRLUT, pc);
239 static u32 (INT_ATTR *fetch)(psxRegisters *regs_, u8 **memRLUT, u32 pc) = fetchNoCache;
241 // Make the timing events trigger faster as we are currently assuming everything
242 // takes one cycle, which is not the case on real hardware.
243 // FIXME: count cache misses, memory latencies, stalls to get rid of this
244 static inline void addCycle(psxRegisters *regs)
246 assert(regs->subCycleStep >= 0x10000);
247 regs->subCycle += regs->subCycleStep;
248 regs->cycle += regs->subCycle >> 16;
249 regs->subCycle &= 0xffff;
252 /**** R3000A Instruction Macros ****/
253 #define _PC_ regs_->pc // The next PC to be executed
255 #define _fOp_(code) ((code >> 26) ) // The opcode part of the instruction register
256 #define _fFunct_(code) ((code ) & 0x3F) // The funct part of the instruction register
257 #define _fRd_(code) ((code >> 11) & 0x1F) // The rd part of the instruction register
258 #define _fRt_(code) ((code >> 16) & 0x1F) // The rt part of the instruction register
259 #define _fRs_(code) ((code >> 21) & 0x1F) // The rs part of the instruction register
260 #define _fSa_(code) ((code >> 6) & 0x1F) // The sa part of the instruction register
261 #define _fIm_(code) ((u16)code) // The immediate part of the instruction register
262 #define _fTarget_(code) (code & 0x03ffffff) // The target part of the instruction register
264 #define _fImm_(code) ((s16)code) // sign-extended immediate
265 #define _fImmU_(code) (code&0xffff) // zero-extended immediate
267 #define _Op_ _fOp_(code)
268 #define _Funct_ _fFunct_(code)
269 #define _Rd_ _fRd_(code)
270 #define _Rt_ _fRt_(code)
271 #define _Rs_ _fRs_(code)
272 #define _Sa_ _fSa_(code)
273 #define _Im_ _fIm_(code)
274 #define _Target_ _fTarget_(code)
276 #define _Imm_ _fImm_(code)
277 #define _ImmU_ _fImmU_(code)
279 #define _rRs_ regs_->GPR.r[_Rs_] // Rs register
280 #define _rRt_ regs_->GPR.r[_Rt_] // Rt register
281 #define _rSa_ regs_->GPR.r[_Sa_] // Sa register
283 #define _rHi_ regs_->GPR.n.hi // The HI register
284 #define _rLo_ regs_->GPR.n.lo // The LO register
286 #define _JumpTarget_ ((_Target_ * 4) + (_PC_ & 0xf0000000)) // Calculates the target during a jump instruction
287 #define _BranchTarget_ ((s16)_Im_ * 4 + _PC_) // Calculates the target during a branch instruction
289 #define _SetLink(x) dloadRt(regs_, x, _PC_ + 4); // Sets the return address in the link register
292 static inline INT_ATTR void name(psxRegisters *regs_, u32 code)
294 // this defines shall be used with the tmp
295 // of the next func (instead of _Funct_...)
296 #define _tFunct_ ((tmp ) & 0x3F) // The funct part of the instruction register
297 #define _tRd_ ((tmp >> 11) & 0x1F) // The rd part of the instruction register
298 #define _tRt_ ((tmp >> 16) & 0x1F) // The rt part of the instruction register
299 #define _tRs_ ((tmp >> 21) & 0x1F) // The rs part of the instruction register
300 #define _tSa_ ((tmp >> 6) & 0x1F) // The sa part of the instruction register
302 #define _i32(x) (s32)(x)
303 #define _u32(x) (u32)(x)
305 #define isBranch(c_) \
306 ((1 <= ((c_) >> 26) && ((c_) >> 26) <= 7) || ((c_) & 0xfc00003e) == 8)
307 #define swap_(a_, b_) { u32 t_ = a_; a_ = b_; b_ = t_; }
309 // tar1 is main branch target, 'code' is opcode in DS
310 static u32 psxBranchNoDelay(psxRegisters *regs_, u32 tar1, u32 code, int *taken) {
313 assert(isBranch(code));
315 switch (code >> 26) {
316 case 0x00: // SPECIAL
323 regs_->GPR.r[_Rd_] = tar1 + 4;
331 regs_->GPR.n.ra = tar1 + 4;
333 return tar1 + (s16)_Im_ * 4;
336 regs_->GPR.n.ra = tar1 + 4;
337 if (_i32(_rRs_) >= 0)
338 return tar1 + (s16)_Im_ * 4;
341 if (rt & 1) { // BGEZ
342 if (_i32(_rRs_) >= 0)
343 return tar1 + (s16)_Im_ * 4;
347 return tar1 + (s16)_Im_ * 4;
353 return (tar1 & 0xf0000000u) + _Target_ * 4;
355 regs_->GPR.n.ra = tar1 + 4;
356 return (tar1 & 0xf0000000u) + _Target_ * 4;
358 if (_i32(_rRs_) == _i32(_rRt_))
359 return tar1 + (s16)_Im_ * 4;
362 if (_i32(_rRs_) != _i32(_rRt_))
363 return tar1 + (s16)_Im_ * 4;
366 if (_i32(_rRs_) <= 0)
367 return tar1 + (s16)_Im_ * 4;
371 return tar1 + (s16)_Im_ * 4;
379 static void psxDoDelayBranch(psxRegisters *regs, u32 tar1, u32 code1) {
383 tar2 = psxBranchNoDelay(regs, tar1, code1, &taken);
389 * taken branch in delay slot:
390 * - execute 1 instruction at tar1
391 * - jump to tar2 (target of branch in delay slot; this branch
392 * has no normal delay slot, instruction at tar1 was fetched instead)
394 for (lim = 0; lim < 8; lim++) {
395 regs->code = code = fetch(regs, psxMemRLUT, tar1);
397 if (likely(!isBranch(code))) {
399 psxBSC[code >> 26](regs, code);
403 tar1 = psxBranchNoDelay(regs, tar2, code, &taken);
409 SysPrintf("Evil chained DS branches @ %08x %08x %08x\n", regs->pc, tar1, tar2);
412 static void doBranch(psxRegisters *regs, u32 tar, enum R3000Abdt taken) {
413 u32 code, pc, pc_final;
415 branchSeen = regs->branching = taken;
416 pc_final = taken == R3000A_BRANCH_TAKEN ? tar : regs->pc + 4;
418 // fetch the delay slot
421 regs->code = code = fetch(regs, psxMemRLUT, pc);
425 // check for branch in delay slot
426 if (unlikely(isBranch(code))) {
428 if (taken == R3000A_BRANCH_TAKEN)
429 psxDoDelayBranch(regs, tar, code);
430 log_unhandled("branch in DS: %08x->%08x\n", pc, regs->pc);
437 psxBSC[code >> 26](regs, code);
439 if (likely(regs->branching != R3000A_BRANCH_NONE_OR_EXCEPTION))
442 regs->CP0.n.Target = pc_final;
448 static void doBranchReg(psxRegisters *regs, u32 tar) {
449 doBranch(regs, tar & ~3, R3000A_BRANCH_TAKEN);
452 static void doBranchRegE(psxRegisters *regs, u32 tar) {
453 if (unlikely(DBR_EN_EXEC(regs->CP0.n.DCIC, tar) &&
454 ((tar ^ regs->CP0.n.BPC) & regs->CP0.n.BPCM) == 0))
455 regs->CP0.n.DCIC |= 0x03;
456 if (unlikely(tar & 3)) {
457 SysPrintf("game crash @%08x, ra=%08x\n", tar, regs->GPR.n.ra);
458 regs->CP0.n.BadVAddr = tar;
459 intException(regs, tar, R3000E_AdEL << 2);
462 doBranch(regs, tar, R3000A_BRANCH_TAKEN);
465 static void addExc(psxRegisters *regs, u32 rt, s32 a1, s32 a2) {
467 if (add_overflow(a1, a2, val)) {
468 //printf("ov %08x + %08x = %08x\n", a1, a2, val);
469 intExceptionInsn(regs, R3000E_Ov << 2);
472 dloadRt(regs, rt, val);
475 static void subExc(psxRegisters *regs, u32 rt, s32 a1, s32 a2) {
477 if (sub_overflow(a1, a2, val)) {
478 intExceptionInsn(regs, R3000E_Ov << 2);
481 dloadRt(regs, rt, val);
484 /*********************************************************
485 * Arithmetic with immediate operand *
486 * Format: OP rt, rs, immediate *
487 *********************************************************/
488 OP(psxADDI) { addExc (regs_, _Rt_, _i32(_rRs_), _Imm_); } // Rt = Rs + Im (Exception on Integer Overflow)
489 OP(psxADDIU) { dloadRt(regs_, _Rt_, _u32(_rRs_) + _Imm_ ); } // Rt = Rs + Im
490 OP(psxANDI) { dloadRt(regs_, _Rt_, _u32(_rRs_) & _ImmU_); } // Rt = Rs And Im
491 OP(psxORI) { dloadRt(regs_, _Rt_, _u32(_rRs_) | _ImmU_); } // Rt = Rs Or Im
492 OP(psxXORI) { dloadRt(regs_, _Rt_, _u32(_rRs_) ^ _ImmU_); } // Rt = Rs Xor Im
493 OP(psxSLTI) { dloadRt(regs_, _Rt_, _i32(_rRs_) < _Imm_ ); } // Rt = Rs < Im (Signed)
494 OP(psxSLTIU) { dloadRt(regs_, _Rt_, _u32(_rRs_) < ((u32)_Imm_)); } // Rt = Rs < Im (Unsigned)
496 /*********************************************************
497 * Register arithmetic *
498 * Format: OP rd, rs, rt *
499 *********************************************************/
500 OP(psxADD) { addExc (regs_, _Rd_, _i32(_rRs_), _i32(_rRt_)); } // Rd = Rs + Rt (Exception on Integer Overflow)
501 OP(psxSUB) { subExc (regs_, _Rd_, _i32(_rRs_), _i32(_rRt_)); } // Rd = Rs - Rt (Exception on Integer Overflow)
502 OP(psxADDU) { dloadRt(regs_, _Rd_, _u32(_rRs_) + _u32(_rRt_)); } // Rd = Rs + Rt
503 OP(psxSUBU) { dloadRt(regs_, _Rd_, _u32(_rRs_) - _u32(_rRt_)); } // Rd = Rs - Rt
504 OP(psxAND) { dloadRt(regs_, _Rd_, _u32(_rRs_) & _u32(_rRt_)); } // Rd = Rs And Rt
505 OP(psxOR) { dloadRt(regs_, _Rd_, _u32(_rRs_) | _u32(_rRt_)); } // Rd = Rs Or Rt
506 OP(psxXOR) { dloadRt(regs_, _Rd_, _u32(_rRs_) ^ _u32(_rRt_)); } // Rd = Rs Xor Rt
507 OP(psxNOR) { dloadRt(regs_, _Rd_, ~_u32(_rRs_ | _u32(_rRt_))); } // Rd = Rs Nor Rt
508 OP(psxSLT) { dloadRt(regs_, _Rd_, _i32(_rRs_) < _i32(_rRt_)); } // Rd = Rs < Rt (Signed)
509 OP(psxSLTU) { dloadRt(regs_, _Rd_, _u32(_rRs_) < _u32(_rRt_)); } // Rd = Rs < Rt (Unsigned)
511 /*********************************************************
512 * Register mult/div & Register trap logic *
513 * Format: OP rs, rt *
514 *********************************************************/
518 if (_rRs_ & 0x80000000) {
524 #if !defined(__arm__) && !defined(__aarch64__)
525 else if (_rRs_ == 0x80000000 && _rRt_ == 0xFFFFFFFF) {
531 _rLo_ = _i32(_rRs_) / _i32(_rRt_);
532 _rHi_ = _i32(_rRs_) % _i32(_rRt_);
537 regs_->muldivBusyCycle = regs_->cycle + 37;
543 _rLo_ = _rRs_ / _rRt_;
544 _rHi_ = _rRs_ % _rRt_;
553 regs_->muldivBusyCycle = regs_->cycle + 37;
554 psxDIVU(regs_, code);
558 u64 res = (s64)_i32(_rRs_) * _i32(_rRt_);
560 regs_->GPR.n.lo = (u32)res;
561 regs_->GPR.n.hi = (u32)(res >> 32);
565 // approximate, but maybe good enough
567 u32 lz = __builtin_clz(((rs ^ ((s32)rs >> 21)) | 1));
568 u32 c = 7 + (2 - (lz / 11)) * 4;
569 regs_->muldivBusyCycle = regs_->cycle + c;
570 psxMULT(regs_, code);
574 u64 res = (u64)_u32(_rRs_) * _u32(_rRt_);
576 regs_->GPR.n.lo = (u32)(res & 0xffffffff);
577 regs_->GPR.n.hi = (u32)((res >> 32) & 0xffffffff);
581 // approximate, but maybe good enough
582 u32 lz = __builtin_clz(_rRs_ | 1);
583 u32 c = 7 + (2 - (lz / 11)) * 4;
584 regs_->muldivBusyCycle = regs_->cycle + c;
585 psxMULTU(regs_, code);
588 /*********************************************************
589 * Register branch logic *
590 * Format: OP rs, offset *
591 *********************************************************/
592 #define BrCond(c) (c) ? R3000A_BRANCH_TAKEN : R3000A_BRANCH_NOT_TAKEN
593 #define RepZBranchi32(op) \
594 doBranch(regs_, _BranchTarget_, BrCond(_i32(_rRs_) op 0));
595 #define RepZBranchLinki32(op) { \
596 s32 temp = _i32(_rRs_); \
599 doBranch(regs_, _BranchTarget_, BrCond(temp op 0)); \
602 OP(psxBGEZ) { RepZBranchi32(>=) } // Branch if Rs >= 0
603 OP(psxBGEZAL) { RepZBranchLinki32(>=) } // Branch if Rs >= 0 and link
604 OP(psxBGTZ) { RepZBranchi32(>) } // Branch if Rs > 0
605 OP(psxBLEZ) { RepZBranchi32(<=) } // Branch if Rs <= 0
606 OP(psxBLTZ) { RepZBranchi32(<) } // Branch if Rs < 0
607 OP(psxBLTZAL) { RepZBranchLinki32(<) } // Branch if Rs < 0 and link
609 /*********************************************************
610 * Shift arithmetic with constant shift *
611 * Format: OP rd, rt, sa *
612 *********************************************************/
613 OP(psxSLL) { dloadRt(regs_, _Rd_, _u32(_rRt_) << _Sa_); } // Rd = Rt << sa
614 OP(psxSRA) { dloadRt(regs_, _Rd_, _i32(_rRt_) >> _Sa_); } // Rd = Rt >> sa (arithmetic)
615 OP(psxSRL) { dloadRt(regs_, _Rd_, _u32(_rRt_) >> _Sa_); } // Rd = Rt >> sa (logical)
617 /*********************************************************
618 * Shift arithmetic with variant register shift *
619 * Format: OP rd, rt, rs *
620 *********************************************************/
621 OP(psxSLLV) { dloadRt(regs_, _Rd_, _u32(_rRt_) << (_u32(_rRs_) & 0x1F)); } // Rd = Rt << rs
622 OP(psxSRAV) { dloadRt(regs_, _Rd_, _i32(_rRt_) >> (_u32(_rRs_) & 0x1F)); } // Rd = Rt >> rs (arithmetic)
623 OP(psxSRLV) { dloadRt(regs_, _Rd_, _u32(_rRt_) >> (_u32(_rRs_) & 0x1F)); } // Rd = Rt >> rs (logical)
625 /*********************************************************
626 * Load higher 16 bits of the first word in GPR with imm *
627 * Format: OP rt, immediate *
628 *********************************************************/
629 OP(psxLUI) { dloadRt(regs_, _Rt_, code << 16); } // Upper halfword of Rt = Im
631 /*********************************************************
632 * Move from HI/LO to GPR *
634 *********************************************************/
635 OP(psxMFHI) { dloadRt(regs_, _Rd_, _rHi_); } // Rd = Hi
636 OP(psxMFLO) { dloadRt(regs_, _Rd_, _rLo_); } // Rd = Lo
638 static void mflohiCheckStall(psxRegisters *regs_)
640 u32 left = regs_->muldivBusyCycle - regs_->cycle;
642 //printf("muldiv stall %u\n", left);
643 regs_->cycle = regs_->muldivBusyCycle;
647 OP(psxMFHI_stall) { mflohiCheckStall(regs_); psxMFHI(regs_, code); }
648 OP(psxMFLO_stall) { mflohiCheckStall(regs_); psxMFLO(regs_, code); }
650 /*********************************************************
651 * Move to GPR to HI/LO & Register jump *
653 *********************************************************/
654 OP(psxMTHI) { _rHi_ = _rRs_; } // Hi = Rs
655 OP(psxMTLO) { _rLo_ = _rRs_; } // Lo = Rs
657 /*********************************************************
658 * Special purpose instructions *
660 *********************************************************/
662 intExceptionInsn(regs_, R3000E_Bp << 2);
666 intExceptionInsn(regs_, R3000E_Syscall << 2);
669 static inline void execI_(u8 **memRLUT, psxRegisters *regs_);
671 static inline void psxTestSWInts(psxRegisters *regs_, int step) {
672 if ((regs_->CP0.n.Cause & regs_->CP0.n.SR & 0x0300) &&
673 (regs_->CP0.n.SR & 0x1)) {
675 execI_(psxMemRLUT, regs_);
676 regs_->CP0.n.Cause &= ~0x7c;
677 intException(regs_, regs_->pc, regs_->CP0.n.Cause);
682 regs_->CP0.n.SR = (regs_->CP0.n.SR & ~0x0f) | ((regs_->CP0.n.SR & 0x3c) >> 2);
683 psxTestSWInts(regs_, 0);
686 /*********************************************************
687 * Register branch logic *
688 * Format: OP rs, rt, offset *
689 *********************************************************/
690 #define RepBranchi32(op) \
691 doBranch(regs_, _BranchTarget_, BrCond(_i32(_rRs_) op _i32(_rRt_)));
693 OP(psxBEQ) { RepBranchi32(==) } // Branch if Rs == Rt
694 OP(psxBNE) { RepBranchi32(!=) } // Branch if Rs != Rt
696 /*********************************************************
698 * Format: OP target *
699 *********************************************************/
700 OP(psxJ) { doBranch(regs_, _JumpTarget_, R3000A_BRANCH_TAKEN); }
704 doBranch(regs_, _JumpTarget_, R3000A_BRANCH_TAKEN);
707 /*********************************************************
709 * Format: OP rs, rd *
710 *********************************************************/
712 doBranchReg(regs_, _rRs_);
717 doBranchRegE(regs_, _rRs_);
722 u32 temp = _u32(_rRs_);
724 if (_Rd_) { _SetLink(_Rd_); }
725 doBranchReg(regs_, temp);
729 u32 temp = _u32(_rRs_);
731 if (_Rd_) { _SetLink(_Rd_); }
732 doBranchRegE(regs_, temp);
735 /*********************************************************
736 *********************************************************/
738 // revisit: incomplete
739 #define BUS_LOCKED_ADDR(a) \
740 ((0x1fc80000u <= (a) && (a) < 0x80000000u) || \
741 (0xc0000000u <= (a) && (a) < 0xfffe0000u))
743 // exception checking order is important
744 static inline int checkLD(psxRegisters *regs, u32 addr, u32 m) {
746 if (unlikely(DBR_EN_LD(regs->CP0.n.DCIC, addr) &&
747 ((addr ^ regs->CP0.n.BDA) & regs->CP0.n.BDAM) == 0)) {
748 regs->CP0.n.DCIC |= 0x0d;
749 bpException = regs->CP0.n.DCIC >> 31;
751 if (unlikely(addr & m)) {
752 regs->CP0.n.BadVAddr = addr;
753 intExceptionInsn(regs, R3000E_AdEL << 2);
756 if (unlikely(bpException)) {
757 intExceptionDebugBp(regs, regs->pc - 4);
760 if (unlikely(BUS_LOCKED_ADDR(addr))) {
761 intException(regs, regs->pc - 4, R3000E_DBE << 2);
767 static inline int checkST(psxRegisters *regs, u32 addr, u32 m) {
769 if (unlikely(DBR_EN_ST(regs->CP0.n.DCIC, addr) &&
770 ((addr ^ regs->CP0.n.BDA) & regs->CP0.n.BDAM) == 0)) {
771 regs->CP0.n.DCIC |= 0x15;
772 bpException = regs->CP0.n.DCIC >> 31;
774 if (unlikely(addr & m)) {
775 regs->CP0.n.BadVAddr = addr;
776 intExceptionInsn(regs, R3000E_AdES << 2);
779 if (unlikely(bpException)) {
780 intExceptionDebugBp(regs, regs->pc - 4);
783 if (unlikely(BUS_LOCKED_ADDR(addr))) {
784 intException(regs, regs->pc - 4, R3000E_DBE << 2);
790 /*********************************************************
791 * Load and store for GPR *
792 * Format: OP rt, offset(base) *
793 *********************************************************/
795 /*********************************************************
796 * Load and store for GPR *
797 * Format: OP rt, offset(base) *
798 *********************************************************/
800 #define _oB_ (regs_->GPR.r[_Rs_] + _Imm_)
802 OP(psxLB) { doLoad(regs_, _Rt_, (s8)psxMemRead8(_oB_)); }
803 OP(psxLBU) { doLoad(regs_, _Rt_, psxMemRead8(_oB_)); }
804 OP(psxLH) { doLoad(regs_, _Rt_, (s16)psxMemRead16(_oB_ & ~1)); }
805 OP(psxLHU) { doLoad(regs_, _Rt_, psxMemRead16(_oB_ & ~1)); }
806 OP(psxLW) { doLoad(regs_, _Rt_, psxMemRead32(_oB_ & ~3)); }
808 OP(psxLBe) { if (checkLD(regs_, _oB_, 0)) doLoad(regs_, _Rt_, (s8)psxMemRead8(_oB_)); }
809 OP(psxLBUe) { if (checkLD(regs_, _oB_, 0)) doLoad(regs_, _Rt_, psxMemRead8(_oB_)); }
810 OP(psxLHe) { if (checkLD(regs_, _oB_, 1)) doLoad(regs_, _Rt_, (s16)psxMemRead16(_oB_)); }
811 OP(psxLHUe) { if (checkLD(regs_, _oB_, 1)) doLoad(regs_, _Rt_, psxMemRead16(_oB_)); }
812 OP(psxLWe) { if (checkLD(regs_, _oB_, 3)) doLoad(regs_, _Rt_, psxMemRead32(_oB_)); }
814 static void doLWL(psxRegisters *regs, u32 rt, u32 addr) {
815 static const u32 LWL_MASK[4] = { 0xffffff, 0xffff, 0xff, 0 };
816 static const u32 LWL_SHIFT[4] = { 24, 16, 8, 0 };
817 u32 shift = addr & 3;
819 u32 oldval = regs->GPR.r[rt];
821 #ifdef HANDLE_LOAD_DELAY
822 int sel = regs->dloadSel;
823 if (regs->dloadReg[sel] == rt)
824 oldval = regs->dloadVal[sel];
826 mem = psxMemRead32(addr & ~3);
827 val = (oldval & LWL_MASK[shift]) | (mem << LWL_SHIFT[shift]);
828 doLoad(regs, rt, val);
831 Mem = 1234. Reg = abcd
833 0 4bcd (mem << 24) | (reg & 0x00ffffff)
834 1 34cd (mem << 16) | (reg & 0x0000ffff)
835 2 234d (mem << 8) | (reg & 0x000000ff)
836 3 1234 (mem ) | (reg & 0x00000000)
840 static void doLWR(psxRegisters *regs, u32 rt, u32 addr) {
841 static const u32 LWR_MASK[4] = { 0, 0xff000000, 0xffff0000, 0xffffff00 };
842 static const u32 LWR_SHIFT[4] = { 0, 8, 16, 24 };
843 u32 shift = addr & 3;
845 u32 oldval = regs->GPR.r[rt];
847 #ifdef HANDLE_LOAD_DELAY
848 int sel = regs->dloadSel;
849 if (regs->dloadReg[sel] == rt)
850 oldval = regs->dloadVal[sel];
852 mem = psxMemRead32(addr & ~3);
853 val = (oldval & LWR_MASK[shift]) | (mem >> LWR_SHIFT[shift]);
854 doLoad(regs, rt, val);
857 Mem = 1234. Reg = abcd
859 0 1234 (mem ) | (reg & 0x00000000)
860 1 a123 (mem >> 8) | (reg & 0xff000000)
861 2 ab12 (mem >> 16) | (reg & 0xffff0000)
862 3 abc1 (mem >> 24) | (reg & 0xffffff00)
866 OP(psxLWL) { doLWL(regs_, _Rt_, _oB_); }
867 OP(psxLWR) { doLWR(regs_, _Rt_, _oB_); }
869 OP(psxLWLe) { if (checkLD(regs_, _oB_ & ~3, 0)) doLWL(regs_, _Rt_, _oB_); }
870 OP(psxLWRe) { if (checkLD(regs_, _oB_ , 0)) doLWR(regs_, _Rt_, _oB_); }
872 OP(psxSB) { psxMemWrite8 (_oB_, _rRt_ & 0xff); }
873 OP(psxSH) { psxMemWrite16(_oB_, _rRt_ & 0xffff); }
874 OP(psxSW) { psxMemWrite32(_oB_, _rRt_); }
876 OP(psxSBe) { if (checkST(regs_, _oB_, 0)) psxMemWrite8 (_oB_, _rRt_ & 0xff); }
877 OP(psxSHe) { if (checkST(regs_, _oB_, 1)) psxMemWrite16(_oB_, _rRt_ & 0xffff); }
878 OP(psxSWe) { if (checkST(regs_, _oB_, 3)) psxMemWrite32(_oB_, _rRt_); }
880 static void doSWL(psxRegisters *regs, u32 rt, u32 addr) {
881 u32 val = regs->GPR.r[rt];
883 case 0: psxMemWrite8( addr , val >> 24); break;
884 case 1: psxMemWrite16(addr & ~3, val >> 16); break;
885 case 2: // revisit: should be a single 24bit write
886 psxMemWrite16(addr & ~3, (val >> 8) & 0xffff);
887 psxMemWrite8( addr , val >> 24); break;
888 case 3: psxMemWrite32(addr & ~3, val); break;
891 Mem = 1234. Reg = abcd
893 0 123a (reg >> 24) | (mem & 0xffffff00)
894 1 12ab (reg >> 16) | (mem & 0xffff0000)
895 2 1abc (reg >> 8) | (mem & 0xff000000)
896 3 abcd (reg ) | (mem & 0x00000000)
900 static void doSWR(psxRegisters *regs, u32 rt, u32 addr) {
901 u32 val = regs->GPR.r[rt];
903 case 0: psxMemWrite32(addr , val); break;
904 case 1: // revisit: should be a single 24bit write
905 psxMemWrite8 (addr , val & 0xff);
906 psxMemWrite16(addr + 1, (val >> 8) & 0xffff); break;
907 case 2: psxMemWrite16(addr , val & 0xffff); break;
908 case 3: psxMemWrite8 (addr , val & 0xff); break;
912 Mem = 1234. Reg = abcd
914 0 abcd (reg ) | (mem & 0x00000000)
915 1 bcd4 (reg << 8) | (mem & 0x000000ff)
916 2 cd34 (reg << 16) | (mem & 0x0000ffff)
917 3 d234 (reg << 24) | (mem & 0x00ffffff)
921 OP(psxSWL) { doSWL(regs_, _Rt_, _oB_); }
922 OP(psxSWR) { doSWR(regs_, _Rt_, _oB_); }
924 OP(psxSWLe) { if (checkST(regs_, _oB_ & ~3, 0)) doSWL(regs_, _Rt_, _oB_); }
925 OP(psxSWRe) { if (checkST(regs_, _oB_ , 0)) doSWR(regs_, _Rt_, _oB_); }
927 /*********************************************************
928 * Moves between GPR and COPx *
929 * Format: OP rt, fs *
930 *********************************************************/
933 if (unlikely(0x00000417u & (1u << r)))
934 intExceptionReservedInsn(regs_);
935 doLoad(regs_, _Rt_, regs_->CP0.r[r]);
938 static void setupCop(u32 sr);
940 void MTC0(psxRegisters *regs_, int reg, u32 val) {
941 // SysPrintf("MTC0 %d: %x\n", reg, val);
944 if (unlikely((regs_->CP0.n.SR ^ val) & (1 << 16)))
945 psxMemOnIsolate((val >> 16) & 1);
946 if (unlikely((regs_->CP0.n.SR ^ val) & (7 << 29)))
948 regs_->CP0.n.SR = val;
949 psxTestSWInts(regs_, 1);
953 regs_->CP0.n.Cause &= ~0x0300;
954 regs_->CP0.n.Cause |= val & 0x0300;
955 psxTestSWInts(regs_, 0);
959 if ((regs_->CP0.n.DCIC ^ val) & 0xff800000)
960 log_unhandled("DCIC: %08x->%08x\n", regs_->CP0.n.DCIC, val);
963 regs_->CP0.r[reg] = val;
968 OP(psxMTC0) { MTC0(regs_, _Rd_, _u32(_rRt_)); }
971 static inline void psxNULLne(psxRegisters *regs) {
972 log_unhandled("unhandled op %08x @%08x\n", regs->code, regs->pc - 4);
975 /*********************************************************
976 * Unknown instruction (would generate an exception) *
978 *********************************************************/
982 intExceptionReservedInsn(regs_);
985 void gteNULL(struct psxCP2Regs *regs) {
986 psxRegisters *regs_ = (psxRegisters *)((u8 *)regs - offsetof(psxRegisters, CP2));
991 psxSPC[_Funct_](regs_, code);
997 u32 op2 = code & 0x1f;
1002 case 0x08: psxNULL(regs_, code); break;
1003 case 0x10: psxRFE(regs_, code); break;
1004 default: psxNULLne(regs_); break;
1009 case 0x00: psxMFC0(regs_, code); break;
1010 case 0x04: psxMTC0(regs_, code); break;
1012 case 0x06: psxNULL(regs_, code); break; // CTC -> exception
1014 case 0x0c: log_unhandled("BC0 %08x @%08x\n", code, regs_->pc - 4);
1015 default: psxNULLne(regs_); break;
1020 // ??? what actually happens here?
1021 log_unhandled("COP1 %08x @%08x\n", code, regs_->pc - 4);
1025 u32 rt = _Rt_, rd = _Rd_, rs = _Rs_;
1027 psxCP2[_Funct_](®s_->CP2);
1031 case 0x00: doLoad(regs_, rt, MFC2(®s_->CP2, rd)); break; // MFC2
1032 case 0x02: doLoad(regs_, rt, regs_->CP2C.r[rd]); break; // CFC2
1033 case 0x04: MTC2(®s_->CP2, regs_->GPR.r[rt], rd); break; // MTC2
1034 case 0x06: CTC2(®s_->CP2, regs_->GPR.r[rt], rd); break; // CTC2
1036 case 0x0c: log_unhandled("BC2 %08x @%08x\n", code, regs_->pc - 4);
1037 default: psxNULLne(regs_); break;
1044 psxCOP2(regs_, code);
1048 MTC2(®s_->CP2, psxMemRead32(_oB_), _Rt_);
1053 gteLWC2(regs_, code);
1056 OP(gteLWC2e_stall) {
1058 if (checkLD(regs_, _oB_, 3))
1059 MTC2(®s_->CP2, psxMemRead32(_oB_), _Rt_);
1063 psxMemWrite32(_oB_, MFC2(®s_->CP2, _Rt_));
1068 gteSWC2(regs_, code);
1071 OP(gteSWC2e_stall) {
1073 if (checkST(regs_, _oB_, 3))
1074 gteSWC2(regs_, code);
1078 // ??? what actually happens here?
1079 log_unhandled("COP3 %08x @%08x\n", code, regs_->pc - 4);
1083 log_unhandled("disabled cop%d @%08x\n", (code >> 26) & 3, regs_->pc - 4);
1084 #ifdef DO_EXCEPTION_RESERVEDI
1085 intExceptionInsn(regs_, R3000E_CpU << 2);
1090 log_unhandled("LWCx %08x @%08x\n", code, regs_->pc - 4);
1091 checkLD(regs_, _oB_, 3);
1095 // does this write something to memory?
1096 log_unhandled("SWCx %08x @%08x\n", code, regs_->pc - 4);
1097 checkST(regs_, _oB_, 3);
1103 case 0x10: psxBLTZAL(regs_, code); break;
1104 case 0x11: psxBGEZAL(regs_, code); break;
1107 psxBGEZ(regs_, code);
1109 psxBLTZ(regs_, code);
1115 if (unlikely(!Config.HLE)) {
1116 psxSWCx(regs_, code);
1119 hleCode = code & 0x03ffffff;
1120 if (hleCode >= (sizeof(psxHLEt) / sizeof(psxHLEt[0]))) {
1121 psxSWCx(regs_, code);
1129 static void (INT_ATTR *psxBSC[64])(psxRegisters *regs_, u32 code) = {
1130 psxSPECIAL, psxREGIMM, psxJ , psxJAL , psxBEQ , psxBNE , psxBLEZ, psxBGTZ,
1131 psxADDI , psxADDIU , psxSLTI, psxSLTIU, psxANDI, psxORI , psxXORI, psxLUI ,
1132 psxCOP0 , psxCOPd , psxCOP2, psxCOPd, psxNULL, psxNULL, psxNULL, psxNULL,
1133 psxNULL , psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
1134 psxLB , psxLH , psxLWL , psxLW , psxLBU , psxLHU , psxLWR , psxNULL,
1135 psxSB , psxSH , psxSWL , psxSW , psxNULL, psxNULL, psxSWR , psxNULL,
1136 psxLWCx , psxLWCx , gteLWC2, psxLWCx , psxNULL, psxNULL, psxNULL, psxNULL,
1137 psxSWCx , psxSWCx , gteSWC2, psxHLE , psxNULL, psxNULL, psxNULL, psxNULL,
1140 static void (INT_ATTR *psxSPC[64])(psxRegisters *regs_, u32 code) = {
1141 psxSLL , psxNULL , psxSRL , psxSRA , psxSLLV , psxNULL , psxSRLV, psxSRAV,
1142 psxJR , psxJALR , psxNULL, psxNULL, psxSYSCALL, psxBREAK, psxNULL, psxNULL,
1143 psxMFHI, psxMTHI , psxMFLO, psxMTLO, psxNULL , psxNULL , psxNULL, psxNULL,
1144 psxMULT, psxMULTU, psxDIV , psxDIVU, psxNULL , psxNULL , psxNULL, psxNULL,
1145 psxADD , psxADDU , psxSUB , psxSUBU, psxAND , psxOR , psxXOR , psxNOR ,
1146 psxNULL, psxNULL , psxSLT , psxSLTU, psxNULL , psxNULL , psxNULL, psxNULL,
1147 psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL,
1148 psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL
1151 void (*psxCP2[64])(struct psxCP2Regs *regs) = {
1152 gteNULL , gteRTPS , gteNULL , gteNULL, gteNULL, gteNULL , gteNCLIP, gteNULL, // 00
1153 gteNULL , gteNULL , gteNULL , gteNULL, gteOP , gteNULL , gteNULL , gteNULL, // 08
1154 gteDPCS , gteINTPL, gteMVMVA, gteNCDS, gteCDP , gteNULL , gteNCDT , gteNULL, // 10
1155 gteNULL , gteNULL , gteNULL , gteNCCS, gteCC , gteNULL , gteNCS , gteNULL, // 18
1156 gteNCT , gteNULL , gteNULL , gteNULL, gteNULL, gteNULL , gteNULL , gteNULL, // 20
1157 gteSQR , gteDCPL , gteDPCT , gteNULL, gteNULL, gteAVSZ3, gteAVSZ4, gteNULL, // 28
1158 gteRTPT , gteNULL , gteNULL , gteNULL, gteNULL, gteNULL , gteNULL , gteNULL, // 30
1159 gteNULL , gteNULL , gteNULL , gteNULL, gteNULL, gteGPF , gteGPL , gteNCCT // 38
1162 ///////////////////////////////////////////
1164 static int intInit() {
1168 static void intReset() {
1169 dloadClear(&psxRegs);
1170 psxRegs.subCycle = 0;
1173 static inline void execI_(u8 **memRLUT, psxRegisters *regs) {
1180 regs->code = fetch(regs, memRLUT, pc);
1181 psxBSC[regs->code >> 26](regs, regs->code);
1184 static inline void execIbp(u8 **memRLUT, psxRegisters *regs) {
1190 if (execBreakCheck(regs, pc))
1194 regs->code = fetch(regs, memRLUT, pc);
1195 psxBSC[regs->code >> 26](regs, regs->code);
1198 static void intExecute() {
1199 psxRegisters *regs_ = &psxRegs;
1200 u8 **memRLUT = psxMemRLUT;
1204 execI_(memRLUT, regs_);
1207 static void intExecuteBp() {
1208 psxRegisters *regs_ = &psxRegs;
1209 u8 **memRLUT = psxMemRLUT;
1213 execIbp(memRLUT, regs_);
1216 void intExecuteBlock(enum blockExecCaller caller) {
1217 psxRegisters *regs_ = &psxRegs;
1218 u8 **memRLUT = psxMemRLUT;
1222 execI_(memRLUT, regs_);
1225 static void intClear(u32 Addr, u32 Size) {
1228 static void intNotify(enum R3000Anote note, void *data) {
1230 case R3000ACPU_NOTIFY_BEFORE_SAVE:
1231 dloadFlush(&psxRegs);
1233 case R3000ACPU_NOTIFY_AFTER_LOAD:
1234 dloadClear(&psxRegs);
1235 psxRegs.subCycle = 0;
1236 setupCop(psxRegs.CP0.n.SR);
1238 case R3000ACPU_NOTIFY_CACHE_ISOLATED: // Armored Core?
1239 memset(&ICache, 0xff, sizeof(ICache));
1241 case R3000ACPU_NOTIFY_CACHE_UNISOLATED:
1246 static void setupCop(u32 sr)
1248 if (sr & (1u << 29))
1249 psxBSC[17] = psxCOP1;
1251 psxBSC[17] = psxCOPd;
1252 if (sr & (1u << 30))
1253 psxBSC[18] = Config.DisableStalls ? psxCOP2 : psxCOP2_stall;
1255 psxBSC[18] = psxCOPd;
1256 if (sr & (1u << 31))
1257 psxBSC[19] = psxCOP3;
1259 psxBSC[19] = psxCOPd;
1262 void intApplyConfig() {
1265 assert(psxSPC[16] == psxMFHI || psxSPC[16] == psxMFHI_stall);
1266 assert(psxSPC[18] == psxMFLO || psxSPC[18] == psxMFLO_stall);
1267 assert(psxSPC[24] == psxMULT || psxSPC[24] == psxMULT_stall);
1268 assert(psxSPC[25] == psxMULTU || psxSPC[25] == psxMULTU_stall);
1269 assert(psxSPC[26] == psxDIV || psxSPC[26] == psxDIV_stall);
1270 assert(psxSPC[27] == psxDIVU || psxSPC[27] == psxDIVU_stall);
1272 if (Config.DisableStalls) {
1273 psxBSC[18] = psxCOP2;
1274 psxBSC[50] = gteLWC2;
1275 psxBSC[58] = gteSWC2;
1276 psxSPC[16] = psxMFHI;
1277 psxSPC[18] = psxMFLO;
1278 psxSPC[24] = psxMULT;
1279 psxSPC[25] = psxMULTU;
1280 psxSPC[26] = psxDIV;
1281 psxSPC[27] = psxDIVU;
1283 psxBSC[18] = psxCOP2_stall;
1284 psxBSC[50] = gteLWC2_stall;
1285 psxBSC[58] = gteSWC2_stall;
1286 psxSPC[16] = psxMFHI_stall;
1287 psxSPC[18] = psxMFLO_stall;
1288 psxSPC[24] = psxMULT_stall;
1289 psxSPC[25] = psxMULTU_stall;
1290 psxSPC[26] = psxDIV_stall;
1291 psxSPC[27] = psxDIVU_stall;
1293 setupCop(psxRegs.CP0.n.SR);
1295 if (Config.PreciseExceptions) {
1296 psxBSC[0x20] = psxLBe;
1297 psxBSC[0x21] = psxLHe;
1298 psxBSC[0x22] = psxLWLe;
1299 psxBSC[0x23] = psxLWe;
1300 psxBSC[0x24] = psxLBUe;
1301 psxBSC[0x25] = psxLHUe;
1302 psxBSC[0x26] = psxLWRe;
1303 psxBSC[0x28] = psxSBe;
1304 psxBSC[0x29] = psxSHe;
1305 psxBSC[0x2a] = psxSWLe;
1306 psxBSC[0x2b] = psxSWe;
1307 psxBSC[0x2e] = psxSWRe;
1308 psxBSC[0x32] = gteLWC2e_stall;
1309 psxBSC[0x3a] = gteSWC2e_stall;
1310 psxSPC[0x08] = psxJRe;
1311 psxSPC[0x09] = psxJALRe;
1312 psxInt.Execute = intExecuteBp;
1314 psxBSC[0x20] = psxLB;
1315 psxBSC[0x21] = psxLH;
1316 psxBSC[0x22] = psxLWL;
1317 psxBSC[0x23] = psxLW;
1318 psxBSC[0x24] = psxLBU;
1319 psxBSC[0x25] = psxLHU;
1320 psxBSC[0x26] = psxLWR;
1321 psxBSC[0x28] = psxSB;
1322 psxBSC[0x29] = psxSH;
1323 psxBSC[0x2a] = psxSWL;
1324 psxBSC[0x2b] = psxSW;
1325 psxBSC[0x2e] = psxSWR;
1326 // LWC2, SWC2 handled by Config.DisableStalls
1327 psxSPC[0x08] = psxJR;
1328 psxSPC[0x09] = psxJALR;
1329 psxInt.Execute = intExecute;
1332 // the dynarec may occasionally call the interpreter, in such a case the
1333 // cache won't work (cache only works right if all fetches go through it)
1334 if (!Config.icache_emulation || psxCpu != &psxInt)
1335 fetch = fetchNoCache;
1337 fetch = fetchICache;
1339 cycle_mult = Config.cycle_multiplier_override && Config.cycle_multiplier == CYCLE_MULT_DEFAULT
1340 ? Config.cycle_multiplier_override : Config.cycle_multiplier;
1341 psxRegs.subCycleStep = 0x10000 * cycle_mult / 100;
1344 static void intShutdown() {
1345 dloadClear(&psxRegs);
1348 // single step (may do several ops in case of a branch or load delay)
1349 // called by asm/dynarec
1350 void execI(psxRegisters *regs) {
1352 execIbp(psxMemRLUT, regs);
1353 } while (regs->dloadReg[0] || regs->dloadReg[1]);
1356 R3000Acpu psxInt = {