psxinterpreter: rework load delays
[pcsx_rearmed.git] / libpcsxcore / psxinterpreter.c
CommitLineData
ef79bbde
P
1/***************************************************************************
2 * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team *
f9ae4f29 3 * Copyright (C) 2023 notaz *
ef79bbde
P
4 * *
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. *
9 * *
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. *
14 * *
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 ***************************************************************************/
20
21/*
22 * PSX assembly interpreter.
23 */
24
25#include "psxcommon.h"
26#include "r3000a.h"
27#include "gte.h"
28#include "psxhle.h"
3968e69e 29#include "psxinterpreter.h"
4cc373dd 30#include <stddef.h>
32631e6a 31#include <assert.h>
905b7c25 32#include "../include/compiler_features.h"
33
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
f9ae4f29 37#define DO_EXCEPTION_ALIGNMENT_BRANCH
38//#define DO_EXCEPTION_ALIGNMENT_DATA
39#define HANDLE_LOAD_DELAY
ef79bbde
P
40
41static int branch = 0;
42static int branch2 = 0;
ef79bbde 43
4cc373dd 44#ifdef __i386__
45#define INT_ATTR __attribute__((regparm(2)))
46#else
47#define INT_ATTR
48#endif
49#ifndef INVALID_PTR
50#define INVALID_PTR NULL
51#endif
52
ef79bbde 53// Subsets
4cc373dd 54static void (INT_ATTR *psxBSC[64])(psxRegisters *regs_, u32 code);
55static void (INT_ATTR *psxSPC[64])(psxRegisters *regs_, u32 code);
56
f9ae4f29 57// load delay
58static void doLoad(psxRegisters *regs, u32 r, u32 val)
59{
60#ifdef HANDLE_LOAD_DELAY
61 int sel = regs->dloadSel ^ 1;
62 assert(regs->dloadReg[sel] == 0);
63 regs->dloadReg[sel] = r;
64 regs->dloadVal[sel] = r ? val : 0;
65 if (regs->dloadReg[sel ^ 1] == r)
66 regs->dloadVal[sel ^ 1] = regs->dloadReg[sel ^ 1] = 0;
67#else
68 regs->GPR.r[r] = r ? val : 0;
69#endif
70}
71
72static void dloadRt(psxRegisters *regs, u32 r, u32 val)
73{
74#ifdef HANDLE_LOAD_DELAY
75 int sel = regs->dloadSel;
76 if (unlikely(regs->dloadReg[sel] == r))
77 regs->dloadVal[sel] = regs->dloadReg[sel] = 0;
78#endif
79 regs->GPR.r[r] = r ? val : 0;
80}
81
82static void dloadStep(psxRegisters *regs)
83{
84#ifdef HANDLE_LOAD_DELAY
85 int sel = regs->dloadSel;
86 regs->GPR.r[regs->dloadReg[sel]] = regs->dloadVal[sel];
87 regs->dloadVal[sel] = regs->dloadReg[sel] = 0;
88 regs->dloadSel ^= 1;
89 assert(regs->GPR.r[0] == 0);
90#endif
91}
92
93static void dloadFlush(psxRegisters *regs)
94{
95#ifdef HANDLE_LOAD_DELAY
96 regs->GPR.r[regs->dloadReg[0]] = regs->dloadVal[0];
97 regs->GPR.r[regs->dloadReg[1]] = regs->dloadVal[1];
98 regs->dloadVal[0] = regs->dloadVal[1] = 0;
99 regs->dloadReg[0] = regs->dloadReg[1] = 0;
100 assert(regs->GPR.r[0] == 0);
101#endif
102}
103
104static void dloadClear(psxRegisters *regs)
105{
106#ifdef HANDLE_LOAD_DELAY
107 regs->dloadVal[0] = regs->dloadVal[1] = 0;
108 regs->dloadReg[0] = regs->dloadReg[1] = 0;
109 regs->dloadSel = 0;
110#endif
111}
112
113static void intException(psxRegisters *regs, u32 pc, u32 cause)
114{
115 dloadFlush(regs);
116 regs->pc = pc;
117 psxException(cause, branch, &regs->CP0);
118}
119
905b7c25 120// get an opcode without triggering exceptions or affecting cache
121u32 intFakeFetch(u32 pc)
122{
123 u8 *base = psxMemRLUT[pc >> 16];
124 u32 *code;
125 if (unlikely(base == INVALID_PTR))
126 return 0; // nop
127 code = (u32 *)(base + (pc & 0xfffc));
128 return SWAP32(*code);
129
130}
131
132static u32 INT_ATTR fetchNoCache(psxRegisters *regs, u8 **memRLUT, u32 pc)
61ad2a61 133{
4cc373dd 134 u8 *base = memRLUT[pc >> 16];
905b7c25 135 u32 *code;
136 if (unlikely(base == INVALID_PTR)) {
137 SysPrintf("game crash @%08x, ra=%08x\n", pc, regs->GPR.n.ra);
f9ae4f29 138 intException(regs, pc, R3000E_IBE << 2);
905b7c25 139 return 0; // execute as nop
140 }
141 code = (u32 *)(base + (pc & 0xfffc));
4cc373dd 142 return SWAP32(*code);
61ad2a61 143}
144
943a507a 145/*
146Formula One 2001 :
147Use old CPU cache code when the RAM location is updated with new code (affects in-game racing)
148*/
9f84fc93 149static struct cache_entry {
150 u32 tag;
151 u32 data[4];
152} ICache[256];
153
905b7c25 154static u32 INT_ATTR fetchICache(psxRegisters *regs, u8 **memRLUT, u32 pc)
943a507a 155{
9f84fc93 156 // cached?
157 if (pc < 0xa0000000)
943a507a 158 {
9f84fc93 159 // this is not how the hardware works but whatever
160 struct cache_entry *entry = &ICache[(pc & 0xff0) >> 4];
161
162 if (((entry->tag ^ pc) & 0xfffffff0) != 0 || pc < entry->tag)
943a507a 163 {
4cc373dd 164 const u8 *base = memRLUT[pc >> 16];
165 const u32 *code;
905b7c25 166 if (unlikely(base == INVALID_PTR)) {
167 SysPrintf("game crash @%08x, ra=%08x\n", pc, regs->GPR.n.ra);
f9ae4f29 168 intException(regs, pc, R3000E_IBE << 2);
905b7c25 169 return 0; // execute as nop
170 }
4cc373dd 171 code = (u32 *)(base + (pc & 0xfff0));
9f84fc93 172
173 entry->tag = pc;
174 // treat as 4 words, although other configurations are said to be possible
175 switch (pc & 0x0c)
176 {
177 case 0x00: entry->data[0] = SWAP32(code[0]);
178 case 0x04: entry->data[1] = SWAP32(code[1]);
179 case 0x08: entry->data[2] = SWAP32(code[2]);
180 case 0x0c: entry->data[3] = SWAP32(code[3]);
181 }
943a507a 182 }
9f84fc93 183 return entry->data[(pc & 0x0f) >> 2];
943a507a 184 }
185
905b7c25 186 return fetchNoCache(regs, memRLUT, pc);
943a507a 187}
61ad2a61 188
905b7c25 189static u32 (INT_ATTR *fetch)(psxRegisters *regs_, u8 **memRLUT, u32 pc) = fetchNoCache;
943a507a 190
d5aeda23 191// Make the timing events trigger faster as we are currently assuming everything
192// takes one cycle, which is not the case on real hardware.
193// FIXME: count cache misses, memory latencies, stalls to get rid of this
194static inline void addCycle(void)
195{
196 assert(psxRegs.subCycleStep >= 0x10000);
197 psxRegs.subCycle += psxRegs.subCycleStep;
198 psxRegs.cycle += psxRegs.subCycle >> 16;
199 psxRegs.subCycle &= 0xffff;
200}
201
4cc373dd 202/**** R3000A Instruction Macros ****/
203#define _PC_ regs_->pc // The next PC to be executed
204
205#define _fOp_(code) ((code >> 26) ) // The opcode part of the instruction register
206#define _fFunct_(code) ((code ) & 0x3F) // The funct part of the instruction register
207#define _fRd_(code) ((code >> 11) & 0x1F) // The rd part of the instruction register
208#define _fRt_(code) ((code >> 16) & 0x1F) // The rt part of the instruction register
209#define _fRs_(code) ((code >> 21) & 0x1F) // The rs part of the instruction register
210#define _fSa_(code) ((code >> 6) & 0x1F) // The sa part of the instruction register
211#define _fIm_(code) ((u16)code) // The immediate part of the instruction register
212#define _fTarget_(code) (code & 0x03ffffff) // The target part of the instruction register
213
214#define _fImm_(code) ((s16)code) // sign-extended immediate
215#define _fImmU_(code) (code&0xffff) // zero-extended immediate
216
217#define _Op_ _fOp_(code)
218#define _Funct_ _fFunct_(code)
219#define _Rd_ _fRd_(code)
220#define _Rt_ _fRt_(code)
221#define _Rs_ _fRs_(code)
222#define _Sa_ _fSa_(code)
223#define _Im_ _fIm_(code)
224#define _Target_ _fTarget_(code)
225
226#define _Imm_ _fImm_(code)
227#define _ImmU_ _fImmU_(code)
228
229#define _rRs_ regs_->GPR.r[_Rs_] // Rs register
230#define _rRt_ regs_->GPR.r[_Rt_] // Rt register
4cc373dd 231#define _rSa_ regs_->GPR.r[_Sa_] // Sa register
4cc373dd 232
233#define _rHi_ regs_->GPR.n.hi // The HI register
234#define _rLo_ regs_->GPR.n.lo // The LO register
235
236#define _JumpTarget_ ((_Target_ * 4) + (_PC_ & 0xf0000000)) // Calculates the target during a jump instruction
237#define _BranchTarget_ ((s16)_Im_ * 4 + _PC_) // Calculates the target during a branch instruction
238
f9ae4f29 239#define _SetLink(x) dloadRt(regs_, x, _PC_ + 4); // Sets the return address in the link register
4cc373dd 240
241#define OP(name) \
242 static inline INT_ATTR void name(psxRegisters *regs_, u32 code)
243
ef79bbde
P
244// this defines shall be used with the tmp
245// of the next func (instead of _Funct_...)
246#define _tFunct_ ((tmp ) & 0x3F) // The funct part of the instruction register
247#define _tRd_ ((tmp >> 11) & 0x1F) // The rd part of the instruction register
248#define _tRt_ ((tmp >> 16) & 0x1F) // The rt part of the instruction register
249#define _tRs_ ((tmp >> 21) & 0x1F) // The rs part of the instruction register
250#define _tSa_ ((tmp >> 6) & 0x1F) // The sa part of the instruction register
251
4cc373dd 252#define _i32(x) (s32)(x)
253#define _u32(x) (u32)(x)
254
b9698f9d 255#define isBranch(c_) \
256 ((1 <= ((c_) >> 26) && ((c_) >> 26) <= 7) || ((c_) & 0xfc00003e) == 8)
257#define swap_(a_, b_) { u32 t_ = a_; a_ = b_; b_ = t_; }
990cb018 258
b9698f9d 259// tar1 is main branch target, 'code' is opcode in DS
260static u32 psxBranchNoDelay(psxRegisters *regs_, u32 tar1, u32 code, int *taken) {
261 u32 temp, rt;
262
263 assert(isBranch(code));
264 *taken = 1;
265 switch (code >> 26) {
990cb018 266 case 0x00: // SPECIAL
267 switch (_Funct_) {
268 case 0x08: // JR
269 return _u32(_rRs_);
270 case 0x09: // JALR
271 temp = _u32(_rRs_);
b9698f9d 272 if (_Rd_)
273 regs_->GPR.r[_Rd_] = tar1 + 4;
990cb018 274 return temp;
275 }
276 break;
277 case 0x01: // REGIMM
b9698f9d 278 rt = _Rt_;
279 switch (rt) {
280 case 0x10: // BLTZAL
281 regs_->GPR.n.ra = tar1 + 4;
990cb018 282 if (_i32(_rRs_) < 0)
b9698f9d 283 return tar1 + (s16)_Im_ * 4;
990cb018 284 break;
b9698f9d 285 case 0x11: // BGEZAL
286 regs_->GPR.n.ra = tar1 + 4;
990cb018 287 if (_i32(_rRs_) >= 0)
b9698f9d 288 return tar1 + (s16)_Im_ * 4;
990cb018 289 break;
b9698f9d 290 default:
291 if (rt & 1) { // BGEZ
292 if (_i32(_rRs_) >= 0)
293 return tar1 + (s16)_Im_ * 4;
990cb018 294 }
b9698f9d 295 else { // BLTZ
296 if (_i32(_rRs_) < 0)
297 return tar1 + (s16)_Im_ * 4;
990cb018 298 }
299 break;
300 }
301 break;
302 case 0x02: // J
b9698f9d 303 return (tar1 & 0xf0000000u) + _Target_ * 4;
990cb018 304 case 0x03: // JAL
b9698f9d 305 regs_->GPR.n.ra = tar1 + 4;
306 return (tar1 & 0xf0000000u) + _Target_ * 4;
990cb018 307 case 0x04: // BEQ
308 if (_i32(_rRs_) == _i32(_rRt_))
b9698f9d 309 return tar1 + (s16)_Im_ * 4;
990cb018 310 break;
311 case 0x05: // BNE
312 if (_i32(_rRs_) != _i32(_rRt_))
b9698f9d 313 return tar1 + (s16)_Im_ * 4;
990cb018 314 break;
315 case 0x06: // BLEZ
316 if (_i32(_rRs_) <= 0)
b9698f9d 317 return tar1 + (s16)_Im_ * 4;
990cb018 318 break;
319 case 0x07: // BGTZ
320 if (_i32(_rRs_) > 0)
b9698f9d 321 return tar1 + (s16)_Im_ * 4;
990cb018 322 break;
323 }
324
b9698f9d 325 *taken = 0;
326 return tar1;
990cb018 327}
328
b9698f9d 329static void psxDoDelayBranch(psxRegisters *regs, u32 tar1, u32 code1) {
330 u32 tar2, code;
331 int taken, lim;
990cb018 332
b9698f9d 333 tar2 = psxBranchNoDelay(regs, tar1, code1, &taken);
334 regs->pc = tar1;
335 if (!taken)
336 return;
990cb018 337
990cb018 338 /*
b9698f9d 339 * taken branch in delay slot:
990cb018 340 * - execute 1 instruction at tar1
341 * - jump to tar2 (target of branch in delay slot; this branch
342 * has no normal delay slot, instruction at tar1 was fetched instead)
343 */
b9698f9d 344 for (lim = 0; lim < 8; lim++) {
345 regs->code = code = fetch(regs, psxMemRLUT, tar1);
346 addCycle();
347 if (likely(!isBranch(code))) {
f9ae4f29 348 dloadStep(regs);
b9698f9d 349 psxBSC[code >> 26](regs, code);
350 regs->pc = tar2;
351 return;
352 }
353 tar1 = psxBranchNoDelay(regs, tar2, code, &taken);
354 regs->pc = tar2;
355 if (!taken)
356 return;
357 swap_(tar1, tar2);
990cb018 358 }
b9698f9d 359 SysPrintf("Evil chained DS branches @ %08x %08x %08x\n", regs->pc, tar1, tar2);
990cb018 360}
361
b9698f9d 362static void doBranch(psxRegisters *regs, u32 tar) {
f9ae4f29 363 u32 code, pc;
ef79bbde
P
364
365 branch2 = branch = 1;
990cb018 366
b9698f9d 367 // fetch the delay slot
368 pc = regs->pc;
369 regs->pc = pc + 4;
370 regs->code = code = fetch(regs, psxMemRLUT, pc);
905b7c25 371
d5aeda23 372 addCycle();
ef79bbde 373
b9698f9d 374 // check for branch in delay slot
375 if (unlikely(isBranch(code))) {
376 psxDoDelayBranch(regs, tar, code);
377 log_unhandled("branch in DS: %08x->%08x\n", pc, regs->pc);
378 branch = 0;
379 psxBranchTest();
380 return;
381 }
382
f9ae4f29 383 dloadStep(regs);
b9698f9d 384 psxBSC[code >> 26](regs, code);
ef79bbde
P
385
386 branch = 0;
b9698f9d 387 regs->pc = tar;
ef79bbde
P
388
389 psxBranchTest();
390}
391
b9698f9d 392static void doBranchReg(psxRegisters *regs, u32 tar) {
f9ae4f29 393#ifdef DO_EXCEPTION_ALIGNMENT_BRANCH
905b7c25 394 if (unlikely(tar & 3)) {
f9ae4f29 395 SysPrintf("game crash @%08x, ra=%08x\n", tar, regs->GPR.n.ra);
396 psxRegs.CP0.n.BadVAddr = tar;
397 intException(regs, tar, R3000E_AdEL << 2);
905b7c25 398 return;
399 }
400#else
401 tar &= ~3;
402#endif
b9698f9d 403 doBranch(regs, tar);
905b7c25 404}
405
406#if __has_builtin(__builtin_add_overflow) || (defined(__GNUC__) && __GNUC__ >= 5)
407#define add_overflow(a, b, r) __builtin_add_overflow(a, b, &(r))
408#define sub_overflow(a, b, r) __builtin_sub_overflow(a, b, &(r))
409#else
410#define add_overflow(a, b, r) ({r = (u32)a + (u32)b; (a ^ ~b) & (a ^ r) & (1u<<31);})
411#define sub_overflow(a, b, r) ({r = (u32)a - (u32)b; (a ^ b) & (a ^ r) & (1u<<31);})
412#endif
413
414static void addExc(psxRegisters *regs, u32 rt, s32 a1, s32 a2) {
f9ae4f29 415 s32 val;
416 if (add_overflow(a1, a2, val)) {
417 //printf("ov %08x + %08x = %08x\n", a1, a2, val);
418 intException(regs, regs->pc - 4, R3000E_Ov << 2);
905b7c25 419 return;
420 }
f9ae4f29 421 dloadRt(regs, rt, val);
905b7c25 422}
423
424static void subExc(psxRegisters *regs, u32 rt, s32 a1, s32 a2) {
f9ae4f29 425 s32 val;
426 if (sub_overflow(a1, a2, val)) {
427 intException(regs, regs->pc - 4, R3000E_Ov << 2);
905b7c25 428 return;
429 }
f9ae4f29 430 dloadRt(regs, rt, val);
905b7c25 431}
432
ef79bbde
P
433/*********************************************************
434* Arithmetic with immediate operand *
435* Format: OP rt, rs, immediate *
436*********************************************************/
f9ae4f29 437OP(psxADDI) { addExc (regs_, _Rt_, _i32(_rRs_), _Imm_); } // Rt = Rs + Im (Exception on Integer Overflow)
438OP(psxADDIU) { dloadRt(regs_, _Rt_, _u32(_rRs_) + _Imm_ ); } // Rt = Rs + Im
439OP(psxANDI) { dloadRt(regs_, _Rt_, _u32(_rRs_) & _ImmU_); } // Rt = Rs And Im
440OP(psxORI) { dloadRt(regs_, _Rt_, _u32(_rRs_) | _ImmU_); } // Rt = Rs Or Im
441OP(psxXORI) { dloadRt(regs_, _Rt_, _u32(_rRs_) ^ _ImmU_); } // Rt = Rs Xor Im
442OP(psxSLTI) { dloadRt(regs_, _Rt_, _i32(_rRs_) < _Imm_ ); } // Rt = Rs < Im (Signed)
443OP(psxSLTIU) { dloadRt(regs_, _Rt_, _u32(_rRs_) < ((u32)_Imm_)); } // Rt = Rs < Im (Unsigned)
ef79bbde
P
444
445/*********************************************************
446* Register arithmetic *
447* Format: OP rd, rs, rt *
448*********************************************************/
f9ae4f29 449OP(psxADD) { addExc (regs_, _Rd_, _i32(_rRs_), _i32(_rRt_)); } // Rd = Rs + Rt (Exception on Integer Overflow)
450OP(psxSUB) { subExc (regs_, _Rd_, _i32(_rRs_), _i32(_rRt_)); } // Rd = Rs - Rt (Exception on Integer Overflow)
451OP(psxADDU) { dloadRt(regs_, _Rd_, _u32(_rRs_) + _u32(_rRt_)); } // Rd = Rs + Rt
452OP(psxSUBU) { dloadRt(regs_, _Rd_, _u32(_rRs_) - _u32(_rRt_)); } // Rd = Rs - Rt
453OP(psxAND) { dloadRt(regs_, _Rd_, _u32(_rRs_) & _u32(_rRt_)); } // Rd = Rs And Rt
454OP(psxOR) { dloadRt(regs_, _Rd_, _u32(_rRs_) | _u32(_rRt_)); } // Rd = Rs Or Rt
455OP(psxXOR) { dloadRt(regs_, _Rd_, _u32(_rRs_) ^ _u32(_rRt_)); } // Rd = Rs Xor Rt
456OP(psxNOR) { dloadRt(regs_, _Rd_, ~_u32(_rRs_ | _u32(_rRt_))); } // Rd = Rs Nor Rt
457OP(psxSLT) { dloadRt(regs_, _Rd_, _i32(_rRs_) < _i32(_rRt_)); } // Rd = Rs < Rt (Signed)
458OP(psxSLTU) { dloadRt(regs_, _Rd_, _u32(_rRs_) < _u32(_rRt_)); } // Rd = Rs < Rt (Unsigned)
ef79bbde
P
459
460/*********************************************************
461* Register mult/div & Register trap logic *
462* Format: OP rs, rt *
463*********************************************************/
4cc373dd 464OP(psxDIV) {
465 if (!_rRt_) {
466 _rHi_ = _rRs_;
467 if (_rRs_ & 0x80000000) {
468 _rLo_ = 1;
469 } else {
470 _rLo_ = 0xFFFFFFFF;
471 }
472 }
a4ae3997 473#if !defined(__arm__) && !defined(__aarch64__)
4cc373dd 474 else if (_rRs_ == 0x80000000 && _rRt_ == 0xFFFFFFFF) {
475 _rLo_ = 0x80000000;
476 _rHi_ = 0;
477 }
a4ae3997 478#endif
4cc373dd 479 else {
480 _rLo_ = _i32(_rRs_) / _i32(_rRt_);
481 _rHi_ = _i32(_rRs_) % _i32(_rRt_);
482 }
ef79bbde
P
483}
484
4cc373dd 485OP(psxDIV_stall) {
486 regs_->muldivBusyCycle = regs_->cycle + 37;
487 psxDIV(regs_, code);
32631e6a 488}
489
4cc373dd 490OP(psxDIVU) {
ef79bbde
P
491 if (_rRt_ != 0) {
492 _rLo_ = _rRs_ / _rRt_;
493 _rHi_ = _rRs_ % _rRt_;
494 }
c7a56f4f 495 else {
4cc373dd 496 _rLo_ = 0xffffffff;
497 _rHi_ = _rRs_;
c7a56f4f 498 }
ef79bbde
P
499}
500
4cc373dd 501OP(psxDIVU_stall) {
502 regs_->muldivBusyCycle = regs_->cycle + 37;
503 psxDIVU(regs_, code);
32631e6a 504}
505
4cc373dd 506OP(psxMULT) {
507 u64 res = (s64)_i32(_rRs_) * _i32(_rRt_);
ef79bbde 508
4cc373dd 509 regs_->GPR.n.lo = (u32)res;
510 regs_->GPR.n.hi = (u32)(res >> 32);
ef79bbde
P
511}
512
4cc373dd 513OP(psxMULT_stall) {
32631e6a 514 // approximate, but maybe good enough
515 u32 rs = _rRs_;
516 u32 lz = __builtin_clz(((rs ^ ((s32)rs >> 21)) | 1));
517 u32 c = 7 + (2 - (lz / 11)) * 4;
4cc373dd 518 regs_->muldivBusyCycle = regs_->cycle + c;
519 psxMULT(regs_, code);
32631e6a 520}
521
4cc373dd 522OP(psxMULTU) {
523 u64 res = (u64)_u32(_rRs_) * _u32(_rRt_);
ef79bbde 524
4cc373dd 525 regs_->GPR.n.lo = (u32)(res & 0xffffffff);
526 regs_->GPR.n.hi = (u32)((res >> 32) & 0xffffffff);
ef79bbde
P
527}
528
4cc373dd 529OP(psxMULTU_stall) {
32631e6a 530 // approximate, but maybe good enough
531 u32 lz = __builtin_clz(_rRs_ | 1);
532 u32 c = 7 + (2 - (lz / 11)) * 4;
4cc373dd 533 regs_->muldivBusyCycle = regs_->cycle + c;
534 psxMULTU(regs_, code);
32631e6a 535}
536
ef79bbde
P
537/*********************************************************
538* Register branch logic *
539* Format: OP rs, offset *
540*********************************************************/
19fae7fc 541#define RepZBranchi32(op) \
542 if(_i32(_rRs_) op 0) \
b9698f9d 543 doBranch(regs_, _BranchTarget_);
19fae7fc 544#define RepZBranchLinki32(op) { \
545 s32 temp = _i32(_rRs_); \
546 _SetLink(31); \
547 if(temp op 0) \
b9698f9d 548 doBranch(regs_, _BranchTarget_); \
19fae7fc 549}
ef79bbde 550
4cc373dd 551OP(psxBGEZ) { RepZBranchi32(>=) } // Branch if Rs >= 0
552OP(psxBGEZAL) { RepZBranchLinki32(>=) } // Branch if Rs >= 0 and link
553OP(psxBGTZ) { RepZBranchi32(>) } // Branch if Rs > 0
554OP(psxBLEZ) { RepZBranchi32(<=) } // Branch if Rs <= 0
555OP(psxBLTZ) { RepZBranchi32(<) } // Branch if Rs < 0
556OP(psxBLTZAL) { RepZBranchLinki32(<) } // Branch if Rs < 0 and link
ef79bbde
P
557
558/*********************************************************
559* Shift arithmetic with constant shift *
560* Format: OP rd, rt, sa *
561*********************************************************/
f9ae4f29 562OP(psxSLL) { dloadRt(regs_, _Rd_, _u32(_rRt_) << _Sa_); } // Rd = Rt << sa
563OP(psxSRA) { dloadRt(regs_, _Rd_, _i32(_rRt_) >> _Sa_); } // Rd = Rt >> sa (arithmetic)
564OP(psxSRL) { dloadRt(regs_, _Rd_, _u32(_rRt_) >> _Sa_); } // Rd = Rt >> sa (logical)
ef79bbde
P
565
566/*********************************************************
567* Shift arithmetic with variant register shift *
568* Format: OP rd, rt, rs *
569*********************************************************/
f9ae4f29 570OP(psxSLLV) { dloadRt(regs_, _Rd_, _u32(_rRt_) << (_u32(_rRs_) & 0x1F)); } // Rd = Rt << rs
571OP(psxSRAV) { dloadRt(regs_, _Rd_, _i32(_rRt_) >> (_u32(_rRs_) & 0x1F)); } // Rd = Rt >> rs (arithmetic)
572OP(psxSRLV) { dloadRt(regs_, _Rd_, _u32(_rRt_) >> (_u32(_rRs_) & 0x1F)); } // Rd = Rt >> rs (logical)
ef79bbde
P
573
574/*********************************************************
575* Load higher 16 bits of the first word in GPR with imm *
576* Format: OP rt, immediate *
577*********************************************************/
f9ae4f29 578OP(psxLUI) { dloadRt(regs_, _Rt_, code << 16); } // Upper halfword of Rt = Im
ef79bbde
P
579
580/*********************************************************
581* Move from HI/LO to GPR *
582* Format: OP rd *
583*********************************************************/
f9ae4f29 584OP(psxMFHI) { dloadRt(regs_, _Rd_, _rHi_); } // Rd = Hi
585OP(psxMFLO) { dloadRt(regs_, _Rd_, _rLo_); } // Rd = Lo
ef79bbde 586
4cc373dd 587static void mflohiCheckStall(psxRegisters *regs_)
32631e6a 588{
4cc373dd 589 u32 left = regs_->muldivBusyCycle - regs_->cycle;
32631e6a 590 if (left <= 37) {
591 //printf("muldiv stall %u\n", left);
4cc373dd 592 regs_->cycle = regs_->muldivBusyCycle;
32631e6a 593 }
594}
595
4cc373dd 596OP(psxMFHI_stall) { mflohiCheckStall(regs_); psxMFHI(regs_, code); }
597OP(psxMFLO_stall) { mflohiCheckStall(regs_); psxMFLO(regs_, code); }
32631e6a 598
ef79bbde
P
599/*********************************************************
600* Move to GPR to HI/LO & Register jump *
601* Format: OP rs *
602*********************************************************/
4cc373dd 603OP(psxMTHI) { _rHi_ = _rRs_; } // Hi = Rs
604OP(psxMTLO) { _rLo_ = _rRs_; } // Lo = Rs
ef79bbde
P
605
606/*********************************************************
607* Special purpose instructions *
608* Format: OP *
609*********************************************************/
4cc373dd 610OP(psxBREAK) {
f9ae4f29 611 intException(regs_, regs_->pc - 4, R3000E_Bp << 2);
ef79bbde
P
612}
613
4cc373dd 614OP(psxSYSCALL) {
f9ae4f29 615 intException(regs_, regs_->pc - 4, R3000E_Syscall << 2);
ef79bbde
P
616}
617
905b7c25 618static inline void execI_(u8 **memRLUT, psxRegisters *regs_);
619
620static inline void psxTestSWInts(psxRegisters *regs_, int step) {
4cc373dd 621 if (regs_->CP0.n.Cause & regs_->CP0.n.Status & 0x0300 &&
622 regs_->CP0.n.Status & 0x1) {
905b7c25 623 if (step)
624 execI_(psxMemRLUT, regs_);
4cc373dd 625 regs_->CP0.n.Cause &= ~0x7c;
f9ae4f29 626 intException(regs_, regs_->pc, regs_->CP0.n.Cause);
4cc373dd 627 }
628}
629
630OP(psxRFE) {
ef79bbde 631// SysPrintf("psxRFE\n");
4cc373dd 632 regs_->CP0.n.Status = (regs_->CP0.n.Status & 0xfffffff0) |
633 ((regs_->CP0.n.Status & 0x3c) >> 2);
905b7c25 634 psxTestSWInts(regs_, 0);
ef79bbde
P
635}
636
637/*********************************************************
638* Register branch logic *
639* Format: OP rs, rt, offset *
640*********************************************************/
b9698f9d 641#define RepBranchi32(op) { \
642 if (_i32(_rRs_) op _i32(_rRt_)) \
643 doBranch(regs_, _BranchTarget_); \
644}
ef79bbde 645
4cc373dd 646OP(psxBEQ) { RepBranchi32(==) } // Branch if Rs == Rt
647OP(psxBNE) { RepBranchi32(!=) } // Branch if Rs != Rt
ef79bbde
P
648
649/*********************************************************
650* Jump to target *
651* Format: OP target *
652*********************************************************/
b9698f9d 653OP(psxJ) { doBranch(regs_, _JumpTarget_); }
654OP(psxJAL) { _SetLink(31); doBranch(regs_, _JumpTarget_); }
ef79bbde
P
655
656/*********************************************************
657* Register jump *
658* Format: OP rs, rd *
659*********************************************************/
4cc373dd 660OP(psxJR) {
b9698f9d 661 doBranchReg(regs_, _rRs_);
ef79bbde
P
662 psxJumpTest();
663}
664
4cc373dd 665OP(psxJALR) {
ef79bbde
P
666 u32 temp = _u32(_rRs_);
667 if (_Rd_) { _SetLink(_Rd_); }
b9698f9d 668 doBranchReg(regs_, temp);
ef79bbde
P
669}
670
671/*********************************************************
672* Load and store for GPR *
673* Format: OP rt, offset(base) *
674*********************************************************/
675
f9ae4f29 676static int algnChkL(psxRegisters *regs, u32 addr, u32 m) {
677 if (unlikely(addr & m)) {
678 log_unhandled("unaligned load %08x @%08x\n", addr, regs->pc - 4);
679#ifdef DO_EXCEPTION_ALIGNMENT_DATA
680 psxRegs.CP0.n.BadVAddr = addr;
681 intException(regs, regs->pc - 4, R3000E_AdEL << 2);
682 return 0;
683#endif
684 }
685 return 1;
686}
687
688static int algnChkS(psxRegisters *regs, u32 addr, u32 m) {
689 if (unlikely(addr & m)) {
690 log_unhandled("unaligned store %08x @%08x\n", addr, regs->pc - 4);
691#ifdef DO_EXCEPTION_ALIGNMENT_DATA
692 psxRegs.CP0.n.BadVAddr = addr;
693 intException(regs, regs->pc - 4, R3000E_AdES << 2);
694 return 0;
695#endif
696 }
697 return 1;
698}
699
700/*********************************************************
701* Load and store for GPR *
702* Format: OP rt, offset(base) *
703*********************************************************/
704
4cc373dd 705#define _oB_ (regs_->GPR.r[_Rs_] + _Imm_)
ef79bbde 706
f9ae4f29 707OP(psxLB) { doLoad(regs_, _Rt_, (s8)psxMemRead8(_oB_)); }
708OP(psxLBU) { doLoad(regs_, _Rt_, psxMemRead8(_oB_)); }
709OP(psxLH) { if (algnChkL(regs_, _oB_, 1)) doLoad(regs_, _Rt_, (s16)psxMemRead16(_oB_)); }
710OP(psxLHU) { if (algnChkL(regs_, _oB_, 1)) doLoad(regs_, _Rt_, psxMemRead16(_oB_)); }
711OP(psxLW) { if (algnChkL(regs_, _oB_, 3)) doLoad(regs_, _Rt_, psxMemRead32(_oB_)); }
ef79bbde 712
4cc373dd 713OP(psxLWL) {
714 static const u32 LWL_MASK[4] = { 0xffffff, 0xffff, 0xff, 0 };
715 static const u32 LWL_SHIFT[4] = { 24, 16, 8, 0 };
f9ae4f29 716 u32 addr = _oB_, val;
ef79bbde
P
717 u32 shift = addr & 3;
718 u32 mem = psxMemRead32(addr & ~3);
f9ae4f29 719 u32 rt = _Rt_;
720 u32 oldval = regs_->GPR.r[rt];
ef79bbde 721
f9ae4f29 722#ifdef HANDLE_LOAD_DELAY
723 int sel = regs_->dloadSel;
724 if (regs_->dloadReg[sel] == rt)
725 oldval = regs_->dloadVal[sel];
726#endif
727 val = (oldval & LWL_MASK[shift]) | (mem << LWL_SHIFT[shift]);
728 doLoad(regs_, rt, val);
ef79bbde
P
729
730 /*
731 Mem = 1234. Reg = abcd
732
733 0 4bcd (mem << 24) | (reg & 0x00ffffff)
734 1 34cd (mem << 16) | (reg & 0x0000ffff)
735 2 234d (mem << 8) | (reg & 0x000000ff)
736 3 1234 (mem ) | (reg & 0x00000000)
737 */
738}
739
4cc373dd 740OP(psxLWR) {
741 static const u32 LWR_MASK[4] = { 0, 0xff000000, 0xffff0000, 0xffffff00 };
742 static const u32 LWR_SHIFT[4] = { 0, 8, 16, 24 };
f9ae4f29 743 u32 addr = _oB_, val;
ef79bbde
P
744 u32 shift = addr & 3;
745 u32 mem = psxMemRead32(addr & ~3);
f9ae4f29 746 u32 rt = _Rt_;
747 u32 oldval = regs_->GPR.r[rt];
ef79bbde 748
f9ae4f29 749#ifdef HANDLE_LOAD_DELAY
750 int sel = regs_->dloadSel;
751 if (regs_->dloadReg[sel] == rt)
752 oldval = regs_->dloadVal[sel];
753#endif
754 val = (oldval & LWR_MASK[shift]) | (mem >> LWR_SHIFT[shift]);
755 doLoad(regs_, rt, val);
ef79bbde
P
756
757 /*
758 Mem = 1234. Reg = abcd
759
760 0 1234 (mem ) | (reg & 0x00000000)
761 1 a123 (mem >> 8) | (reg & 0xff000000)
762 2 ab12 (mem >> 16) | (reg & 0xffff0000)
763 3 abc1 (mem >> 24) | (reg & 0xffffff00)
764 */
765}
766
f9ae4f29 767OP(psxSB) { psxMemWrite8 (_oB_, _rRt_ & 0xff); }
768OP(psxSH) { if (algnChkS(regs_, _oB_, 1)) psxMemWrite16(_oB_, _rRt_ & 0xffff); }
769OP(psxSW) { if (algnChkS(regs_, _oB_, 3)) psxMemWrite32(_oB_, _rRt_); }
ef79bbde 770
f9ae4f29 771// FIXME: this rmw implementation is wrong and would break on io like fifos
4cc373dd 772OP(psxSWL) {
773 static const u32 SWL_MASK[4] = { 0xffffff00, 0xffff0000, 0xff000000, 0 };
774 static const u32 SWL_SHIFT[4] = { 24, 16, 8, 0 };
ef79bbde
P
775 u32 addr = _oB_;
776 u32 shift = addr & 3;
777 u32 mem = psxMemRead32(addr & ~3);
778
779 psxMemWrite32(addr & ~3, (_u32(_rRt_) >> SWL_SHIFT[shift]) |
780 ( mem & SWL_MASK[shift]) );
781 /*
782 Mem = 1234. Reg = abcd
783
784 0 123a (reg >> 24) | (mem & 0xffffff00)
785 1 12ab (reg >> 16) | (mem & 0xffff0000)
786 2 1abc (reg >> 8) | (mem & 0xff000000)
787 3 abcd (reg ) | (mem & 0x00000000)
788 */
789}
790
4cc373dd 791OP(psxSWR) {
792 static const u32 SWR_MASK[4] = { 0, 0xff, 0xffff, 0xffffff };
793 static const u32 SWR_SHIFT[4] = { 0, 8, 16, 24 };
ef79bbde
P
794 u32 addr = _oB_;
795 u32 shift = addr & 3;
796 u32 mem = psxMemRead32(addr & ~3);
797
798 psxMemWrite32(addr & ~3, (_u32(_rRt_) << SWR_SHIFT[shift]) |
799 ( mem & SWR_MASK[shift]) );
800
801 /*
802 Mem = 1234. Reg = abcd
803
804 0 abcd (reg ) | (mem & 0x00000000)
805 1 bcd4 (reg << 8) | (mem & 0x000000ff)
806 2 cd34 (reg << 16) | (mem & 0x0000ffff)
807 3 d234 (reg << 24) | (mem & 0x00ffffff)
808 */
809}
810
811/*********************************************************
812* Moves between GPR and COPx *
813* Format: OP rt, fs *
814*********************************************************/
905b7c25 815OP(psxMFC0) {
816 u32 r = _Rd_;
817#ifdef DO_EXCEPTION_RESERVEDI
f9ae4f29 818 if (unlikely(r == 0))
819 intException(regs_, regs_->pc - 4, R3000E_RI << 2);
905b7c25 820#endif
f9ae4f29 821 doLoad(regs_, _Rt_, regs_->CP0.r[r]);
905b7c25 822}
823
f9ae4f29 824OP(psxCFC0) { doLoad(regs_, _Rt_, regs_->CP0.r[_Rd_]); }
ef79bbde 825
905b7c25 826static void setupCop(u32 sr);
827
4cc373dd 828void MTC0(psxRegisters *regs_, int reg, u32 val) {
ef79bbde
P
829// SysPrintf("MTC0 %d: %x\n", reg, val);
830 switch (reg) {
831 case 12: // Status
905b7c25 832 if (unlikely((regs_->CP0.n.Status ^ val) & (1 << 16)))
679d5ee3 833 psxMemOnIsolate((val >> 16) & 1);
905b7c25 834 if (unlikely((regs_->CP0.n.Status ^ val) & (7 << 29)))
835 setupCop(val);
679d5ee3 836 regs_->CP0.n.Status = val;
905b7c25 837 psxTestSWInts(regs_, 1);
ef79bbde
P
838 break;
839
840 case 13: // Cause
4cc373dd 841 regs_->CP0.n.Cause &= ~0x0300;
842 regs_->CP0.n.Cause |= val & 0x0300;
905b7c25 843 psxTestSWInts(regs_, 0);
ef79bbde
P
844 break;
845
846 default:
4cc373dd 847 regs_->CP0.r[reg] = val;
ef79bbde
P
848 break;
849 }
850}
851
4cc373dd 852OP(psxMTC0) { MTC0(regs_, _Rd_, _u32(_rRt_)); }
853OP(psxCTC0) { MTC0(regs_, _Rd_, _u32(_rRt_)); }
ef79bbde
P
854
855/*********************************************************
905b7c25 856* Unknown instruction (would generate an exception) *
ef79bbde
P
857* Format: ? *
858*********************************************************/
4cc373dd 859static inline void psxNULL_(void) {
905b7c25 860 //printf("op %08x @%08x\n", psxRegs.code, psxRegs.pc);
861}
862
863OP(psxNULL) {
864 psxNULL_();
865#ifdef DO_EXCEPTION_RESERVEDI
f9ae4f29 866 intException(regs_, regs_->pc - 4, R3000E_RI << 2);
ef79bbde
P
867#endif
868}
869
905b7c25 870void gteNULL(struct psxCP2Regs *regs) {
871 psxNULL_();
872}
ef79bbde 873
4cc373dd 874OP(psxSPECIAL) {
875 psxSPC[_Funct_](regs_, code);
ef79bbde
P
876}
877
4cc373dd 878OP(psxCOP0) {
879 switch (_Rs_) {
880 case 0x00: psxMFC0(regs_, code); break;
881 case 0x02: psxCFC0(regs_, code); break;
882 case 0x04: psxMTC0(regs_, code); break;
883 case 0x06: psxCTC0(regs_, code); break;
884 case 0x10: psxRFE(regs_, code); break;
885 default: psxNULL_(); break;
886 }
ef79bbde
P
887}
888
905b7c25 889OP(psxLWC0) {
890 // MTC0(regs_, _Rt_, psxMemRead32(_oB_)); // ?
891 log_unhandled("LWC0 %08x\n", code);
892}
893
894OP(psxCOP1) {
895 // ??? what actually happens here?
896}
897
898OP(psxCOP1d) {
899#ifdef DO_EXCEPTION_RESERVEDI
f9ae4f29 900 intException(regs_, regs_->pc - 4, (1<<28) | (R3000E_RI << 2));
905b7c25 901#endif
902}
903
4cc373dd 904OP(psxCOP2) {
905 psxCP2[_Funct_](&regs_->CP2);
32631e6a 906}
907
4cc373dd 908OP(psxCOP2_stall) {
81dbbf4c 909 u32 f = _Funct_;
32631e6a 910 gteCheckStall(f);
4cc373dd 911 psxCP2[f](&regs_->CP2);
912}
913
905b7c25 914OP(psxCOP2d) {
915#ifdef DO_EXCEPTION_RESERVEDI
f9ae4f29 916 intException(regs_, regs_->pc - 4, (2<<28) | (R3000E_RI << 2));
905b7c25 917#endif
918}
919
4cc373dd 920OP(gteMFC2) {
f9ae4f29 921 doLoad(regs_, _Rt_, MFC2(&regs_->CP2, _Rd_));
4cc373dd 922}
923
924OP(gteCFC2) {
f9ae4f29 925 doLoad(regs_, _Rt_, regs_->CP2C.r[_Rd_]);
4cc373dd 926}
927
928OP(gteMTC2) {
929 MTC2(&regs_->CP2, regs_->GPR.r[_Rt_], _Rd_);
930}
931
932OP(gteCTC2) {
933 CTC2(&regs_->CP2, regs_->GPR.r[_Rt_], _Rd_);
934}
935
936OP(gteLWC2) {
937 MTC2(&regs_->CP2, psxMemRead32(_oB_), _Rt_);
938}
939
940OP(gteSWC2) {
941 psxMemWrite32(_oB_, MFC2(&regs_->CP2, _Rt_));
942}
943
944OP(gteLWC2_stall) {
945 gteCheckStall(0);
946 gteLWC2(regs_, code);
ef79bbde
P
947}
948
4cc373dd 949OP(gteSWC2_stall) {
950 gteCheckStall(0);
951 gteSWC2(regs_, code);
952}
953
905b7c25 954OP(psxCOP3) {
955 // ??? what actually happens here?
956}
957
958OP(psxCOP3d) {
959#ifdef DO_EXCEPTION_RESERVEDI
f9ae4f29 960 intException(regs_, regs_->pc - 4, (3<<28) | (R3000E_RI << 2));
905b7c25 961#endif
962}
963
964OP(psxLWCx) {
965 // does this read memory?
966 log_unhandled("LWCx %08x\n", code);
967}
968
969OP(psxSWCx) {
970 // does this write something to memory?
971 log_unhandled("SWCx %08x\n", code);
972}
973
4cc373dd 974static void psxBASIC(struct psxCP2Regs *cp2regs) {
975 psxRegisters *regs_ = (void *)((char *)cp2regs - offsetof(psxRegisters, CP2));
976 u32 code = regs_->code;
977 assert(regs_ == &psxRegs);
978 switch (_Rs_) {
979 case 0x00: gteMFC2(regs_, code); break;
980 case 0x02: gteCFC2(regs_, code); break;
981 case 0x04: gteMTC2(regs_, code); break;
982 case 0x06: gteCTC2(regs_, code); break;
983 default: psxNULL_(); break;
984 }
985}
986
987OP(psxREGIMM) {
19fae7fc 988 u32 rt = _Rt_;
989 switch (rt) {
4cc373dd 990 case 0x10: psxBLTZAL(regs_, code); break;
991 case 0x11: psxBGEZAL(regs_, code); break;
19fae7fc 992 default:
993 if (rt & 1)
994 psxBGEZ(regs_, code);
995 else
996 psxBLTZ(regs_, code);
4cc373dd 997 }
ef79bbde
P
998}
999
4cc373dd 1000OP(psxHLE) {
905b7c25 1001 u32 hleCode;
1002 if (unlikely(!Config.HLE)) {
1003 psxSWCx(regs_, code);
1004 return;
1005 }
1006 hleCode = code & 0x03ffffff;
1007 if (hleCode >= (sizeof(psxHLEt) / sizeof(psxHLEt[0]))) {
1008 psxSWCx(regs_, code);
1009 return;
1010 }
1011 psxHLEt[hleCode]();
ef79bbde
P
1012}
1013
4cc373dd 1014static void (INT_ATTR *psxBSC[64])(psxRegisters *regs_, u32 code) = {
ef79bbde
P
1015 psxSPECIAL, psxREGIMM, psxJ , psxJAL , psxBEQ , psxBNE , psxBLEZ, psxBGTZ,
1016 psxADDI , psxADDIU , psxSLTI, psxSLTIU, psxANDI, psxORI , psxXORI, psxLUI ,
905b7c25 1017 psxCOP0 , psxCOP1d , psxCOP2, psxCOP3d, psxNULL, psxCOP1d,psxCOP2d,psxCOP3d,
1018 psxNULL , psxCOP1d , psxCOP2d,psxCOP3d, psxNULL, psxCOP1d,psxCOP2d,psxCOP3d,
1019 psxLB , psxLH , psxLWL , psxLW , psxLBU , psxLHU , psxLWR , psxCOP3d,
1020 psxSB , psxSH , psxSWL , psxSW , psxNULL, psxCOP1d,psxSWR , psxCOP3d,
1021 psxLWC0 , psxLWCx , gteLWC2, psxLWCx , psxNULL, psxCOP1d,psxCOP2d,psxCOP3d,
1022 psxSWCx , psxSWCx , gteSWC2, psxHLE , psxNULL, psxCOP1d,psxCOP2d,psxCOP3d,
ef79bbde
P
1023};
1024
4cc373dd 1025static void (INT_ATTR *psxSPC[64])(psxRegisters *regs_, u32 code) = {
ef79bbde
P
1026 psxSLL , psxNULL , psxSRL , psxSRA , psxSLLV , psxNULL , psxSRLV, psxSRAV,
1027 psxJR , psxJALR , psxNULL, psxNULL, psxSYSCALL, psxBREAK, psxNULL, psxNULL,
1028 psxMFHI, psxMTHI , psxMFLO, psxMTLO, psxNULL , psxNULL , psxNULL, psxNULL,
1029 psxMULT, psxMULTU, psxDIV , psxDIVU, psxNULL , psxNULL , psxNULL, psxNULL,
1030 psxADD , psxADDU , psxSUB , psxSUBU, psxAND , psxOR , psxXOR , psxNOR ,
1031 psxNULL, psxNULL , psxSLT , psxSLTU, psxNULL , psxNULL , psxNULL, psxNULL,
1032 psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL,
1033 psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL
1034};
1035
6c0eefaf 1036void (*psxCP2[64])(struct psxCP2Regs *regs) = {
4cc373dd 1037 psxBASIC, gteRTPS , gteNULL , gteNULL, gteNULL, gteNULL , gteNCLIP, gteNULL, // 00
1038 gteNULL , gteNULL , gteNULL , gteNULL, gteOP , gteNULL , gteNULL , gteNULL, // 08
1039 gteDPCS , gteINTPL, gteMVMVA, gteNCDS, gteCDP , gteNULL , gteNCDT , gteNULL, // 10
1040 gteNULL , gteNULL , gteNULL , gteNCCS, gteCC , gteNULL , gteNCS , gteNULL, // 18
1041 gteNCT , gteNULL , gteNULL , gteNULL, gteNULL, gteNULL , gteNULL , gteNULL, // 20
1042 gteSQR , gteDCPL , gteDPCT , gteNULL, gteNULL, gteAVSZ3, gteAVSZ4, gteNULL, // 28
1043 gteRTPT , gteNULL , gteNULL , gteNULL, gteNULL, gteNULL , gteNULL , gteNULL, // 30
1044 gteNULL , gteNULL , gteNULL , gteNULL, gteNULL, gteGPF , gteGPL , gteNCCT // 38
ef79bbde
P
1045};
1046
ef79bbde
P
1047///////////////////////////////////////////
1048
1049static int intInit() {
1050 return 0;
1051}
1052
1053static void intReset() {
f9ae4f29 1054 dloadClear(&psxRegs);
ef79bbde
P
1055}
1056
4cc373dd 1057static inline void execI_(u8 **memRLUT, psxRegisters *regs_) {
905b7c25 1058 u32 pc = regs_->pc;
4cc373dd 1059 regs_->pc += 4;
905b7c25 1060 regs_->code = fetch(regs_, memRLUT, pc);
1061
d5aeda23 1062 addCycle();
4cc373dd 1063
f9ae4f29 1064 dloadStep(regs_);
4cc373dd 1065 psxBSC[regs_->code >> 26](regs_, regs_->code);
1066}
1067
1068static void intExecute() {
1069 psxRegisters *regs_ = &psxRegs;
1070 u8 **memRLUT = psxMemRLUT;
796a91ef 1071 extern int stop;
4cc373dd 1072
1073 while (!stop)
1074 execI_(memRLUT, regs_);
ef79bbde
P
1075}
1076
da65071f 1077void intExecuteBlock(enum blockExecCaller caller) {
4cc373dd 1078 psxRegisters *regs_ = &psxRegs;
1079 u8 **memRLUT = psxMemRLUT;
1080
ef79bbde 1081 branch2 = 0;
4cc373dd 1082 while (!branch2)
1083 execI_(memRLUT, regs_);
ef79bbde
P
1084}
1085
1086static void intClear(u32 Addr, u32 Size) {
1087}
1088
980f7a58 1089static void intNotify(enum R3000Anote note, void *data) {
1090 switch (note) {
f9ae4f29 1091 case R3000ACPU_NOTIFY_BEFORE_SAVE:
1092 dloadFlush(&psxRegs);
1093 break;
980f7a58 1094 case R3000ACPU_NOTIFY_AFTER_LOAD:
f9ae4f29 1095 dloadClear(&psxRegs);
905b7c25 1096 setupCop(psxRegs.CP0.n.Status);
1097 // fallthrough
1098 case R3000ACPU_NOTIFY_CACHE_ISOLATED: // Armored Core?
9f84fc93 1099 memset(&ICache, 0xff, sizeof(ICache));
980f7a58 1100 break;
1101 case R3000ACPU_NOTIFY_CACHE_UNISOLATED:
980f7a58 1102 break;
943a507a 1103 }
943a507a 1104}
1105
905b7c25 1106static void setupCop(u32 sr)
1107{
1108 if (sr & (1u << 29))
1109 psxBSC[17] = psxCOP1;
1110 else
1111 psxBSC[17] = psxCOP1d;
1112 if (sr & (1u << 30))
1113 psxBSC[18] = Config.DisableStalls ? psxCOP2 : psxCOP2_stall;
1114 else
1115 psxBSC[18] = psxCOP2d;
1116 if (sr & (1u << 31))
1117 psxBSC[19] = psxCOP3;
1118 else
1119 psxBSC[19] = psxCOP3d;
1120}
1121
61ad2a61 1122void intApplyConfig() {
d5aeda23 1123 int cycle_mult;
1124
32631e6a 1125 assert(psxBSC[50] == gteLWC2 || psxBSC[50] == gteLWC2_stall);
1126 assert(psxBSC[58] == gteSWC2 || psxBSC[58] == gteSWC2_stall);
1127 assert(psxSPC[16] == psxMFHI || psxSPC[16] == psxMFHI_stall);
1128 assert(psxSPC[18] == psxMFLO || psxSPC[18] == psxMFLO_stall);
1129 assert(psxSPC[24] == psxMULT || psxSPC[24] == psxMULT_stall);
1130 assert(psxSPC[25] == psxMULTU || psxSPC[25] == psxMULTU_stall);
1131 assert(psxSPC[26] == psxDIV || psxSPC[26] == psxDIV_stall);
1132 assert(psxSPC[27] == psxDIVU || psxSPC[27] == psxDIVU_stall);
1133
1134 if (Config.DisableStalls) {
1135 psxBSC[18] = psxCOP2;
1136 psxBSC[50] = gteLWC2;
1137 psxBSC[58] = gteSWC2;
1138 psxSPC[16] = psxMFHI;
1139 psxSPC[18] = psxMFLO;
1140 psxSPC[24] = psxMULT;
1141 psxSPC[25] = psxMULTU;
1142 psxSPC[26] = psxDIV;
1143 psxSPC[27] = psxDIVU;
1144 } else {
1145 psxBSC[18] = psxCOP2_stall;
1146 psxBSC[50] = gteLWC2_stall;
1147 psxBSC[58] = gteSWC2_stall;
1148 psxSPC[16] = psxMFHI_stall;
1149 psxSPC[18] = psxMFLO_stall;
1150 psxSPC[24] = psxMULT_stall;
1151 psxSPC[25] = psxMULTU_stall;
1152 psxSPC[26] = psxDIV_stall;
1153 psxSPC[27] = psxDIVU_stall;
1154 }
905b7c25 1155 setupCop(psxRegs.CP0.n.Status);
61ad2a61 1156
1157 // dynarec may occasionally call the interpreter, in such a case the
1158 // cache won't work (cache only works right if all fetches go through it)
1159 if (!Config.icache_emulation || psxCpu != &psxInt)
1160 fetch = fetchNoCache;
1161 else
1162 fetch = fetchICache;
d5aeda23 1163
1164 cycle_mult = Config.cycle_multiplier_override && Config.cycle_multiplier == CYCLE_MULT_DEFAULT
1165 ? Config.cycle_multiplier_override : Config.cycle_multiplier;
1166 psxRegs.subCycleStep = 0x10000 * cycle_mult / 100;
32631e6a 1167}
1168
ef79bbde
P
1169static void intShutdown() {
1170}
1171
4cc373dd 1172// single step (may do several ops in case of a branch)
4600ba03 1173void execI() {
4cc373dd 1174 execI_(psxMemRLUT, &psxRegs);
ef79bbde
P
1175}
1176
1177R3000Acpu psxInt = {
1178 intInit,
1179 intReset,
1180 intExecute,
1181 intExecuteBlock,
1182 intClear,
943a507a 1183 intNotify,
61ad2a61 1184 intApplyConfig,
ef79bbde
P
1185 intShutdown
1186};