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