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