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