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