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