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