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