psxinterpreter: use cycle_multiplier also
[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 }
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
4cc373dd 405 regs_->code = code = fetch(psxMemRLUT, 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
484 debugI();
485
486 /*
487 * Branch in delay slot:
488 * - execute 1 instruction at tar1
489 * - jump to tar2 (target of branch in delay slot; this branch
490 * has no normal delay slot, instruction at tar1 was fetched instead)
491 */
492 psxRegs.pc = tar1;
4cc373dd 493 tmp1 = psxBranchNoDelay(&psxRegs);
990cb018 494 if (tmp1 == (u32)-1) {
495 return psxDelayBranchExec(tar2);
496 }
497 debugI();
d5aeda23 498 addCycle();
990cb018 499
500 /*
501 * Got a branch at tar1:
502 * - execute 1 instruction at tar2
503 * - jump to target of that branch (tmp1)
504 */
505 psxRegs.pc = tar2;
4cc373dd 506 tmp2 = psxBranchNoDelay(&psxRegs);
990cb018 507 if (tmp2 == (u32)-1) {
508 return psxDelayBranchExec(tmp1);
509 }
510 debugI();
d5aeda23 511 addCycle();
990cb018 512
513 /*
514 * Got a branch at tar2:
515 * - execute 1 instruction at tmp1
516 * - jump to target of that branch (tmp2)
517 */
518 psxRegs.pc = tmp1;
519 return psxDelayBranchExec(tmp2);
520}
521
4600ba03 522static void doBranch(u32 tar) {
4cc373dd 523 u32 tmp, code;
ef79bbde
P
524
525 branch2 = branch = 1;
526 branchPC = tar;
527
990cb018 528 // check for branch in delay slot
529 if (psxDelayBranchTest(tar))
530 return;
531
4cc373dd 532 psxRegs.code = code = fetch(psxMemRLUT, psxRegs.pc);
ef79bbde
P
533
534 debugI();
535
536 psxRegs.pc += 4;
d5aeda23 537 addCycle();
ef79bbde
P
538
539 // check for load delay
540 tmp = psxRegs.code >> 26;
541 switch (tmp) {
542 case 0x10: // COP0
543 switch (_Rs_) {
544 case 0x00: // MFC0
545 case 0x02: // CFC0
546 psxDelayTest(_Rt_, branchPC);
547 return;
548 }
549 break;
550 case 0x12: // COP2
551 switch (_Funct_) {
552 case 0x00:
553 switch (_Rs_) {
554 case 0x00: // MFC2
555 case 0x02: // CFC2
556 psxDelayTest(_Rt_, branchPC);
557 return;
558 }
559 break;
560 }
561 break;
562 case 0x32: // LWC2
563 psxDelayTest(_Rt_, branchPC);
564 return;
565 default:
566 if (tmp >= 0x20 && tmp <= 0x26) { // LB/LH/LWL/LW/LBU/LHU/LWR
567 psxDelayTest(_Rt_, branchPC);
568 return;
569 }
570 break;
571 }
572
4cc373dd 573 psxBSC[psxRegs.code >> 26](&psxRegs, psxRegs.code);
ef79bbde
P
574
575 branch = 0;
576 psxRegs.pc = branchPC;
577
578 psxBranchTest();
579}
580
581/*********************************************************
582* Arithmetic with immediate operand *
583* Format: OP rt, rs, immediate *
584*********************************************************/
4cc373dd 585OP(psxADDI) { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im (Exception on Integer Overflow)
586OP(psxADDIU) { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im
587OP(psxANDI) { if (!_Rt_) return; _rRt_ = _u32(_rRs_) & _ImmU_; } // Rt = Rs And Im
588OP(psxORI) { if (!_Rt_) return; _rRt_ = _u32(_rRs_) | _ImmU_; } // Rt = Rs Or Im
589OP(psxXORI) { if (!_Rt_) return; _rRt_ = _u32(_rRs_) ^ _ImmU_; } // Rt = Rs Xor Im
590OP(psxSLTI) { if (!_Rt_) return; _rRt_ = _i32(_rRs_) < _Imm_ ; } // Rt = Rs < Im (Signed)
591OP(psxSLTIU) { if (!_Rt_) return; _rRt_ = _u32(_rRs_) < ((u32)_Imm_); } // Rt = Rs < Im (Unsigned)
ef79bbde
P
592
593/*********************************************************
594* Register arithmetic *
595* Format: OP rd, rs, rt *
596*********************************************************/
4cc373dd 597OP(psxADD) { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt (Exception on Integer Overflow)
598OP(psxADDU) { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt
599OP(psxSUB) { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt (Exception on Integer Overflow)
600OP(psxSUBU) { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt
601OP(psxAND) { if (!_Rd_) return; _rRd_ = _u32(_rRs_) & _u32(_rRt_); } // Rd = Rs And Rt
602OP(psxOR) { if (!_Rd_) return; _rRd_ = _u32(_rRs_) | _u32(_rRt_); } // Rd = Rs Or Rt
603OP(psxXOR) { if (!_Rd_) return; _rRd_ = _u32(_rRs_) ^ _u32(_rRt_); } // Rd = Rs Xor Rt
604OP(psxNOR) { if (!_Rd_) return; _rRd_ =~(_u32(_rRs_) | _u32(_rRt_)); }// Rd = Rs Nor Rt
605OP(psxSLT) { if (!_Rd_) return; _rRd_ = _i32(_rRs_) < _i32(_rRt_); } // Rd = Rs < Rt (Signed)
606OP(psxSLTU) { if (!_Rd_) return; _rRd_ = _u32(_rRs_) < _u32(_rRt_); } // Rd = Rs < Rt (Unsigned)
ef79bbde
P
607
608/*********************************************************
609* Register mult/div & Register trap logic *
610* Format: OP rs, rt *
611*********************************************************/
4cc373dd 612OP(psxDIV) {
613 if (!_rRt_) {
614 _rHi_ = _rRs_;
615 if (_rRs_ & 0x80000000) {
616 _rLo_ = 1;
617 } else {
618 _rLo_ = 0xFFFFFFFF;
619 }
620 }
a4ae3997 621#if !defined(__arm__) && !defined(__aarch64__)
4cc373dd 622 else if (_rRs_ == 0x80000000 && _rRt_ == 0xFFFFFFFF) {
623 _rLo_ = 0x80000000;
624 _rHi_ = 0;
625 }
a4ae3997 626#endif
4cc373dd 627 else {
628 _rLo_ = _i32(_rRs_) / _i32(_rRt_);
629 _rHi_ = _i32(_rRs_) % _i32(_rRt_);
630 }
ef79bbde
P
631}
632
4cc373dd 633OP(psxDIV_stall) {
634 regs_->muldivBusyCycle = regs_->cycle + 37;
635 psxDIV(regs_, code);
32631e6a 636}
637
4cc373dd 638OP(psxDIVU) {
ef79bbde
P
639 if (_rRt_ != 0) {
640 _rLo_ = _rRs_ / _rRt_;
641 _rHi_ = _rRs_ % _rRt_;
642 }
c7a56f4f 643 else {
4cc373dd 644 _rLo_ = 0xffffffff;
645 _rHi_ = _rRs_;
c7a56f4f 646 }
ef79bbde
P
647}
648
4cc373dd 649OP(psxDIVU_stall) {
650 regs_->muldivBusyCycle = regs_->cycle + 37;
651 psxDIVU(regs_, code);
32631e6a 652}
653
4cc373dd 654OP(psxMULT) {
655 u64 res = (s64)_i32(_rRs_) * _i32(_rRt_);
ef79bbde 656
4cc373dd 657 regs_->GPR.n.lo = (u32)res;
658 regs_->GPR.n.hi = (u32)(res >> 32);
ef79bbde
P
659}
660
4cc373dd 661OP(psxMULT_stall) {
32631e6a 662 // approximate, but maybe good enough
663 u32 rs = _rRs_;
664 u32 lz = __builtin_clz(((rs ^ ((s32)rs >> 21)) | 1));
665 u32 c = 7 + (2 - (lz / 11)) * 4;
4cc373dd 666 regs_->muldivBusyCycle = regs_->cycle + c;
667 psxMULT(regs_, code);
32631e6a 668}
669
4cc373dd 670OP(psxMULTU) {
671 u64 res = (u64)_u32(_rRs_) * _u32(_rRt_);
ef79bbde 672
4cc373dd 673 regs_->GPR.n.lo = (u32)(res & 0xffffffff);
674 regs_->GPR.n.hi = (u32)((res >> 32) & 0xffffffff);
ef79bbde
P
675}
676
4cc373dd 677OP(psxMULTU_stall) {
32631e6a 678 // approximate, but maybe good enough
679 u32 lz = __builtin_clz(_rRs_ | 1);
680 u32 c = 7 + (2 - (lz / 11)) * 4;
4cc373dd 681 regs_->muldivBusyCycle = regs_->cycle + c;
682 psxMULTU(regs_, code);
32631e6a 683}
684
ef79bbde
P
685/*********************************************************
686* Register branch logic *
687* Format: OP rs, offset *
688*********************************************************/
689#define RepZBranchi32(op) if(_i32(_rRs_) op 0) doBranch(_BranchTarget_);
943a507a 690#define RepZBranchLinki32(op) { _SetLink(31); if(_i32(_rRs_) op 0) { doBranch(_BranchTarget_); } }
ef79bbde 691
4cc373dd 692OP(psxBGEZ) { RepZBranchi32(>=) } // Branch if Rs >= 0
693OP(psxBGEZAL) { RepZBranchLinki32(>=) } // Branch if Rs >= 0 and link
694OP(psxBGTZ) { RepZBranchi32(>) } // Branch if Rs > 0
695OP(psxBLEZ) { RepZBranchi32(<=) } // Branch if Rs <= 0
696OP(psxBLTZ) { RepZBranchi32(<) } // Branch if Rs < 0
697OP(psxBLTZAL) { RepZBranchLinki32(<) } // Branch if Rs < 0 and link
ef79bbde
P
698
699/*********************************************************
700* Shift arithmetic with constant shift *
701* Format: OP rd, rt, sa *
702*********************************************************/
4cc373dd 703OP(psxSLL) { if (!_Rd_) return; _rRd_ = _u32(_rRt_) << _Sa_; } // Rd = Rt << sa
704OP(psxSRA) { if (!_Rd_) return; _rRd_ = _i32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (arithmetic)
705OP(psxSRL) { if (!_Rd_) return; _rRd_ = _u32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (logical)
ef79bbde
P
706
707/*********************************************************
708* Shift arithmetic with variant register shift *
709* Format: OP rd, rt, rs *
710*********************************************************/
4cc373dd 711OP(psxSLLV) { if (!_Rd_) return; _rRd_ = _u32(_rRt_) << (_u32(_rRs_) & 0x1F); } // Rd = Rt << rs
712OP(psxSRAV) { if (!_Rd_) return; _rRd_ = _i32(_rRt_) >> (_u32(_rRs_) & 0x1F); } // Rd = Rt >> rs (arithmetic)
713OP(psxSRLV) { if (!_Rd_) return; _rRd_ = _u32(_rRt_) >> (_u32(_rRs_) & 0x1F); } // Rd = Rt >> rs (logical)
ef79bbde
P
714
715/*********************************************************
716* Load higher 16 bits of the first word in GPR with imm *
717* Format: OP rt, immediate *
718*********************************************************/
4cc373dd 719OP(psxLUI) { if (!_Rt_) return; _rRt_ = code << 16; } // Upper halfword of Rt = Im
ef79bbde
P
720
721/*********************************************************
722* Move from HI/LO to GPR *
723* Format: OP rd *
724*********************************************************/
4cc373dd 725OP(psxMFHI) { if (!_Rd_) return; _rRd_ = _rHi_; } // Rd = Hi
726OP(psxMFLO) { if (!_Rd_) return; _rRd_ = _rLo_; } // Rd = Lo
ef79bbde 727
4cc373dd 728static void mflohiCheckStall(psxRegisters *regs_)
32631e6a 729{
4cc373dd 730 u32 left = regs_->muldivBusyCycle - regs_->cycle;
32631e6a 731 if (left <= 37) {
732 //printf("muldiv stall %u\n", left);
4cc373dd 733 regs_->cycle = regs_->muldivBusyCycle;
32631e6a 734 }
735}
736
4cc373dd 737OP(psxMFHI_stall) { mflohiCheckStall(regs_); psxMFHI(regs_, code); }
738OP(psxMFLO_stall) { mflohiCheckStall(regs_); psxMFLO(regs_, code); }
32631e6a 739
ef79bbde
P
740/*********************************************************
741* Move to GPR to HI/LO & Register jump *
742* Format: OP rs *
743*********************************************************/
4cc373dd 744OP(psxMTHI) { _rHi_ = _rRs_; } // Hi = Rs
745OP(psxMTLO) { _rLo_ = _rRs_; } // Lo = Rs
ef79bbde
P
746
747/*********************************************************
748* Special purpose instructions *
749* Format: OP *
750*********************************************************/
4cc373dd 751OP(psxBREAK) {
752 regs_->pc -= 4;
943a507a 753 psxException(0x24, branch);
ef79bbde
P
754}
755
4cc373dd 756OP(psxSYSCALL) {
757 regs_->pc -= 4;
ef79bbde
P
758 psxException(0x20, branch);
759}
760
4cc373dd 761static inline void psxTestSWInts(psxRegisters *regs_) {
762 if (regs_->CP0.n.Cause & regs_->CP0.n.Status & 0x0300 &&
763 regs_->CP0.n.Status & 0x1) {
764 regs_->CP0.n.Cause &= ~0x7c;
765 psxException(regs_->CP0.n.Cause, branch);
766 }
767}
768
769OP(psxRFE) {
ef79bbde 770// SysPrintf("psxRFE\n");
4cc373dd 771 regs_->CP0.n.Status = (regs_->CP0.n.Status & 0xfffffff0) |
772 ((regs_->CP0.n.Status & 0x3c) >> 2);
773 psxTestSWInts(regs_);
ef79bbde
P
774}
775
776/*********************************************************
777* Register branch logic *
778* Format: OP rs, rt, offset *
779*********************************************************/
780#define RepBranchi32(op) if(_i32(_rRs_) op _i32(_rRt_)) doBranch(_BranchTarget_);
781
4cc373dd 782OP(psxBEQ) { RepBranchi32(==) } // Branch if Rs == Rt
783OP(psxBNE) { RepBranchi32(!=) } // Branch if Rs != Rt
ef79bbde
P
784
785/*********************************************************
786* Jump to target *
787* Format: OP target *
788*********************************************************/
4cc373dd 789OP(psxJ) { doBranch(_JumpTarget_); }
790OP(psxJAL) { _SetLink(31); doBranch(_JumpTarget_); }
ef79bbde
P
791
792/*********************************************************
793* Register jump *
794* Format: OP rs, rd *
795*********************************************************/
4cc373dd 796OP(psxJR) {
943a507a 797 doBranch(_rRs_ & ~3);
ef79bbde
P
798 psxJumpTest();
799}
800
4cc373dd 801OP(psxJALR) {
ef79bbde
P
802 u32 temp = _u32(_rRs_);
803 if (_Rd_) { _SetLink(_Rd_); }
943a507a 804 doBranch(temp & ~3);
ef79bbde
P
805}
806
807/*********************************************************
808* Load and store for GPR *
809* Format: OP rt, offset(base) *
810*********************************************************/
811
4cc373dd 812#define _oB_ (regs_->GPR.r[_Rs_] + _Imm_)
ef79bbde 813
4cc373dd 814OP(psxLB) { u32 v = (s8)psxMemRead8(_oB_); if (_Rt_) _rRt_ = v; }
815OP(psxLBU) { u32 v = psxMemRead8(_oB_); if (_Rt_) _rRt_ = v; }
816OP(psxLH) { u32 v = (s16)psxMemRead16(_oB_); if (_Rt_) _rRt_ = v; }
817OP(psxLHU) { u32 v = psxMemRead16(_oB_); if (_Rt_) _rRt_ = v; }
818OP(psxLW) { u32 v = psxMemRead32(_oB_); if (_Rt_) _rRt_ = v; }
ef79bbde 819
4cc373dd 820OP(psxLWL) {
821 static const u32 LWL_MASK[4] = { 0xffffff, 0xffff, 0xff, 0 };
822 static const u32 LWL_SHIFT[4] = { 24, 16, 8, 0 };
ef79bbde
P
823 u32 addr = _oB_;
824 u32 shift = addr & 3;
825 u32 mem = psxMemRead32(addr & ~3);
826
827 if (!_Rt_) return;
4cc373dd 828 _rRt_ = (_u32(_rRt_) & LWL_MASK[shift]) | (mem << LWL_SHIFT[shift]);
ef79bbde
P
829
830 /*
831 Mem = 1234. Reg = abcd
832
833 0 4bcd (mem << 24) | (reg & 0x00ffffff)
834 1 34cd (mem << 16) | (reg & 0x0000ffff)
835 2 234d (mem << 8) | (reg & 0x000000ff)
836 3 1234 (mem ) | (reg & 0x00000000)
837 */
838}
839
4cc373dd 840OP(psxLWR) {
841 static const u32 LWR_MASK[4] = { 0, 0xff000000, 0xffff0000, 0xffffff00 };
842 static const u32 LWR_SHIFT[4] = { 0, 8, 16, 24 };
ef79bbde
P
843 u32 addr = _oB_;
844 u32 shift = addr & 3;
845 u32 mem = psxMemRead32(addr & ~3);
846
847 if (!_Rt_) return;
4cc373dd 848 _rRt_ = (_u32(_rRt_) & LWR_MASK[shift]) | (mem >> LWR_SHIFT[shift]);
ef79bbde
P
849
850 /*
851 Mem = 1234. Reg = abcd
852
853 0 1234 (mem ) | (reg & 0x00000000)
854 1 a123 (mem >> 8) | (reg & 0xff000000)
855 2 ab12 (mem >> 16) | (reg & 0xffff0000)
856 3 abc1 (mem >> 24) | (reg & 0xffffff00)
857 */
858}
859
4cc373dd 860OP(psxSB) { psxMemWrite8 (_oB_, _rRt_ & 0xff); }
861OP(psxSH) { psxMemWrite16(_oB_, _rRt_ & 0xffff); }
862OP(psxSW) { psxMemWrite32(_oB_, _rRt_); }
ef79bbde 863
4cc373dd 864OP(psxSWL) {
865 static const u32 SWL_MASK[4] = { 0xffffff00, 0xffff0000, 0xff000000, 0 };
866 static const u32 SWL_SHIFT[4] = { 24, 16, 8, 0 };
ef79bbde
P
867 u32 addr = _oB_;
868 u32 shift = addr & 3;
869 u32 mem = psxMemRead32(addr & ~3);
870
871 psxMemWrite32(addr & ~3, (_u32(_rRt_) >> SWL_SHIFT[shift]) |
872 ( mem & SWL_MASK[shift]) );
873 /*
874 Mem = 1234. Reg = abcd
875
876 0 123a (reg >> 24) | (mem & 0xffffff00)
877 1 12ab (reg >> 16) | (mem & 0xffff0000)
878 2 1abc (reg >> 8) | (mem & 0xff000000)
879 3 abcd (reg ) | (mem & 0x00000000)
880 */
881}
882
4cc373dd 883OP(psxSWR) {
884 static const u32 SWR_MASK[4] = { 0, 0xff, 0xffff, 0xffffff };
885 static const u32 SWR_SHIFT[4] = { 0, 8, 16, 24 };
ef79bbde
P
886 u32 addr = _oB_;
887 u32 shift = addr & 3;
888 u32 mem = psxMemRead32(addr & ~3);
889
890 psxMemWrite32(addr & ~3, (_u32(_rRt_) << SWR_SHIFT[shift]) |
891 ( mem & SWR_MASK[shift]) );
892
893 /*
894 Mem = 1234. Reg = abcd
895
896 0 abcd (reg ) | (mem & 0x00000000)
897 1 bcd4 (reg << 8) | (mem & 0x000000ff)
898 2 cd34 (reg << 16) | (mem & 0x0000ffff)
899 3 d234 (reg << 24) | (mem & 0x00ffffff)
900 */
901}
902
903/*********************************************************
904* Moves between GPR and COPx *
905* Format: OP rt, fs *
906*********************************************************/
4cc373dd 907OP(psxMFC0) { if (!_Rt_) return; _rRt_ = _rFs_; }
908OP(psxCFC0) { if (!_Rt_) return; _rRt_ = _rFs_; }
ef79bbde 909
4cc373dd 910void MTC0(psxRegisters *regs_, int reg, u32 val) {
ef79bbde
P
911// SysPrintf("MTC0 %d: %x\n", reg, val);
912 switch (reg) {
913 case 12: // Status
4cc373dd 914 regs_->CP0.r[12] = val;
915 psxTestSWInts(regs_);
ef79bbde
P
916 break;
917
918 case 13: // Cause
4cc373dd 919 regs_->CP0.n.Cause &= ~0x0300;
920 regs_->CP0.n.Cause |= val & 0x0300;
921 psxTestSWInts(regs_);
ef79bbde
P
922 break;
923
924 default:
4cc373dd 925 regs_->CP0.r[reg] = val;
ef79bbde
P
926 break;
927 }
928}
929
4cc373dd 930OP(psxMTC0) { MTC0(regs_, _Rd_, _u32(_rRt_)); }
931OP(psxCTC0) { MTC0(regs_, _Rd_, _u32(_rRt_)); }
ef79bbde
P
932
933/*********************************************************
934* Unknow instruction (would generate an exception) *
935* Format: ? *
936*********************************************************/
4cc373dd 937static inline void psxNULL_(void) {
ef79bbde
P
938#ifdef PSXCPU_LOG
939 PSXCPU_LOG("psx: Unimplemented op %x\n", psxRegs.code);
940#endif
941}
942
4cc373dd 943OP(psxNULL) { psxNULL_(); }
944void gteNULL(struct psxCP2Regs *regs) { psxNULL_(); }
ef79bbde 945
4cc373dd 946OP(psxSPECIAL) {
947 psxSPC[_Funct_](regs_, code);
ef79bbde
P
948}
949
4cc373dd 950OP(psxCOP0) {
951 switch (_Rs_) {
952 case 0x00: psxMFC0(regs_, code); break;
953 case 0x02: psxCFC0(regs_, code); break;
954 case 0x04: psxMTC0(regs_, code); break;
955 case 0x06: psxCTC0(regs_, code); break;
956 case 0x10: psxRFE(regs_, code); break;
957 default: psxNULL_(); break;
958 }
ef79bbde
P
959}
960
4cc373dd 961OP(psxCOP2) {
962 psxCP2[_Funct_](&regs_->CP2);
32631e6a 963}
964
4cc373dd 965OP(psxCOP2_stall) {
81dbbf4c 966 u32 f = _Funct_;
32631e6a 967 gteCheckStall(f);
4cc373dd 968 psxCP2[f](&regs_->CP2);
969}
970
971OP(gteMFC2) {
972 if (!_Rt_) return;
973 regs_->GPR.r[_Rt_] = MFC2(&regs_->CP2, _Rd_);
974}
975
976OP(gteCFC2) {
977 if (!_Rt_) return;
978 regs_->GPR.r[_Rt_] = regs_->CP2C.r[_Rd_];
979}
980
981OP(gteMTC2) {
982 MTC2(&regs_->CP2, regs_->GPR.r[_Rt_], _Rd_);
983}
984
985OP(gteCTC2) {
986 CTC2(&regs_->CP2, regs_->GPR.r[_Rt_], _Rd_);
987}
988
989OP(gteLWC2) {
990 MTC2(&regs_->CP2, psxMemRead32(_oB_), _Rt_);
991}
992
993OP(gteSWC2) {
994 psxMemWrite32(_oB_, MFC2(&regs_->CP2, _Rt_));
995}
996
997OP(gteLWC2_stall) {
998 gteCheckStall(0);
999 gteLWC2(regs_, code);
ef79bbde
P
1000}
1001
4cc373dd 1002OP(gteSWC2_stall) {
1003 gteCheckStall(0);
1004 gteSWC2(regs_, code);
1005}
1006
1007static void psxBASIC(struct psxCP2Regs *cp2regs) {
1008 psxRegisters *regs_ = (void *)((char *)cp2regs - offsetof(psxRegisters, CP2));
1009 u32 code = regs_->code;
1010 assert(regs_ == &psxRegs);
1011 switch (_Rs_) {
1012 case 0x00: gteMFC2(regs_, code); break;
1013 case 0x02: gteCFC2(regs_, code); break;
1014 case 0x04: gteMTC2(regs_, code); break;
1015 case 0x06: gteCTC2(regs_, code); break;
1016 default: psxNULL_(); break;
1017 }
1018}
1019
1020OP(psxREGIMM) {
1021 switch (_Rt_) {
1022 case 0x00: psxBLTZ(regs_, code); break;
1023 case 0x01: psxBGEZ(regs_, code); break;
1024 case 0x10: psxBLTZAL(regs_, code); break;
1025 case 0x11: psxBGEZAL(regs_, code); break;
1026 default: psxNULL_(); break;
1027 }
ef79bbde
P
1028}
1029
4cc373dd 1030OP(psxHLE) {
1031 uint32_t hleCode = code & 0x03ffffff;
dd79da89 1032 if (hleCode >= (sizeof(psxHLEt) / sizeof(psxHLEt[0]))) {
4cc373dd 1033 psxNULL_();
dd79da89 1034 } else {
1035 psxHLEt[hleCode]();
1036 }
ef79bbde
P
1037}
1038
4cc373dd 1039static void (INT_ATTR *psxBSC[64])(psxRegisters *regs_, u32 code) = {
ef79bbde
P
1040 psxSPECIAL, psxREGIMM, psxJ , psxJAL , psxBEQ , psxBNE , psxBLEZ, psxBGTZ,
1041 psxADDI , psxADDIU , psxSLTI, psxSLTIU, psxANDI, psxORI , psxXORI, psxLUI ,
1042 psxCOP0 , psxNULL , psxCOP2, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL,
1043 psxNULL , psxNULL , psxNULL, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL,
1044 psxLB , psxLH , psxLWL , psxLW , psxLBU , psxLHU , psxLWR , psxNULL,
1045 psxSB , psxSH , psxSWL , psxSW , psxNULL, psxNULL, psxSWR , psxNULL,
1046 psxNULL , psxNULL , gteLWC2, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL,
1047 psxNULL , psxNULL , gteSWC2, psxHLE , psxNULL, psxNULL, psxNULL, psxNULL
1048};
1049
4cc373dd 1050static void (INT_ATTR *psxSPC[64])(psxRegisters *regs_, u32 code) = {
ef79bbde
P
1051 psxSLL , psxNULL , psxSRL , psxSRA , psxSLLV , psxNULL , psxSRLV, psxSRAV,
1052 psxJR , psxJALR , psxNULL, psxNULL, psxSYSCALL, psxBREAK, psxNULL, psxNULL,
1053 psxMFHI, psxMTHI , psxMFLO, psxMTLO, psxNULL , psxNULL , psxNULL, psxNULL,
1054 psxMULT, psxMULTU, psxDIV , psxDIVU, psxNULL , psxNULL , psxNULL, psxNULL,
1055 psxADD , psxADDU , psxSUB , psxSUBU, psxAND , psxOR , psxXOR , psxNOR ,
1056 psxNULL, psxNULL , psxSLT , psxSLTU, psxNULL , psxNULL , psxNULL, psxNULL,
1057 psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL,
1058 psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL
1059};
1060
6c0eefaf 1061void (*psxCP2[64])(struct psxCP2Regs *regs) = {
4cc373dd 1062 psxBASIC, gteRTPS , gteNULL , gteNULL, gteNULL, gteNULL , gteNCLIP, gteNULL, // 00
1063 gteNULL , gteNULL , gteNULL , gteNULL, gteOP , gteNULL , gteNULL , gteNULL, // 08
1064 gteDPCS , gteINTPL, gteMVMVA, gteNCDS, gteCDP , gteNULL , gteNCDT , gteNULL, // 10
1065 gteNULL , gteNULL , gteNULL , gteNCCS, gteCC , gteNULL , gteNCS , gteNULL, // 18
1066 gteNCT , gteNULL , gteNULL , gteNULL, gteNULL, gteNULL , gteNULL , gteNULL, // 20
1067 gteSQR , gteDCPL , gteDPCT , gteNULL, gteNULL, gteAVSZ3, gteAVSZ4, gteNULL, // 28
1068 gteRTPT , gteNULL , gteNULL , gteNULL, gteNULL, gteNULL , gteNULL , gteNULL, // 30
1069 gteNULL , gteNULL , gteNULL , gteNULL, gteNULL, gteGPF , gteGPL , gteNCCT // 38
ef79bbde
P
1070};
1071
ef79bbde
P
1072///////////////////////////////////////////
1073
1074static int intInit() {
1075 return 0;
1076}
1077
1078static void intReset() {
9f84fc93 1079 memset(&ICache, 0xff, sizeof(ICache));
ef79bbde
P
1080}
1081
4cc373dd 1082static inline void execI_(u8 **memRLUT, psxRegisters *regs_) {
1083 regs_->code = fetch(memRLUT, regs_->pc);
1084
1085 debugI();
1086
1087 if (Config.Debug) ProcessDebug();
1088
1089 regs_->pc += 4;
d5aeda23 1090 addCycle();
4cc373dd 1091
1092 psxBSC[regs_->code >> 26](regs_, regs_->code);
1093}
1094
1095static void intExecute() {
1096 psxRegisters *regs_ = &psxRegs;
1097 u8 **memRLUT = psxMemRLUT;
796a91ef 1098 extern int stop;
4cc373dd 1099
1100 while (!stop)
1101 execI_(memRLUT, regs_);
ef79bbde
P
1102}
1103
4cc373dd 1104static void intExecuteBlock() {
1105 psxRegisters *regs_ = &psxRegs;
1106 u8 **memRLUT = psxMemRLUT;
1107
ef79bbde 1108 branch2 = 0;
4cc373dd 1109 while (!branch2)
1110 execI_(memRLUT, regs_);
ef79bbde
P
1111}
1112
1113static void intClear(u32 Addr, u32 Size) {
1114}
1115
943a507a 1116void intNotify (int note, void *data) {
943a507a 1117 /* Gameblabla - Only clear the icache if it's isolated */
1118 if (note == R3000ACPU_NOTIFY_CACHE_ISOLATED)
1119 {
9f84fc93 1120 memset(&ICache, 0xff, sizeof(ICache));
943a507a 1121 }
943a507a 1122}
1123
61ad2a61 1124void intApplyConfig() {
d5aeda23 1125 int cycle_mult;
1126
32631e6a 1127 assert(psxBSC[18] == psxCOP2 || psxBSC[18] == psxCOP2_stall);
1128 assert(psxBSC[50] == gteLWC2 || psxBSC[50] == gteLWC2_stall);
1129 assert(psxBSC[58] == gteSWC2 || psxBSC[58] == gteSWC2_stall);
1130 assert(psxSPC[16] == psxMFHI || psxSPC[16] == psxMFHI_stall);
1131 assert(psxSPC[18] == psxMFLO || psxSPC[18] == psxMFLO_stall);
1132 assert(psxSPC[24] == psxMULT || psxSPC[24] == psxMULT_stall);
1133 assert(psxSPC[25] == psxMULTU || psxSPC[25] == psxMULTU_stall);
1134 assert(psxSPC[26] == psxDIV || psxSPC[26] == psxDIV_stall);
1135 assert(psxSPC[27] == psxDIVU || psxSPC[27] == psxDIVU_stall);
1136
1137 if (Config.DisableStalls) {
1138 psxBSC[18] = psxCOP2;
1139 psxBSC[50] = gteLWC2;
1140 psxBSC[58] = gteSWC2;
1141 psxSPC[16] = psxMFHI;
1142 psxSPC[18] = psxMFLO;
1143 psxSPC[24] = psxMULT;
1144 psxSPC[25] = psxMULTU;
1145 psxSPC[26] = psxDIV;
1146 psxSPC[27] = psxDIVU;
1147 } else {
1148 psxBSC[18] = psxCOP2_stall;
1149 psxBSC[50] = gteLWC2_stall;
1150 psxBSC[58] = gteSWC2_stall;
1151 psxSPC[16] = psxMFHI_stall;
1152 psxSPC[18] = psxMFLO_stall;
1153 psxSPC[24] = psxMULT_stall;
1154 psxSPC[25] = psxMULTU_stall;
1155 psxSPC[26] = psxDIV_stall;
1156 psxSPC[27] = psxDIVU_stall;
1157 }
61ad2a61 1158
1159 // dynarec may occasionally call the interpreter, in such a case the
1160 // cache won't work (cache only works right if all fetches go through it)
1161 if (!Config.icache_emulation || psxCpu != &psxInt)
1162 fetch = fetchNoCache;
1163 else
1164 fetch = fetchICache;
d5aeda23 1165
1166 cycle_mult = Config.cycle_multiplier_override && Config.cycle_multiplier == CYCLE_MULT_DEFAULT
1167 ? Config.cycle_multiplier_override : Config.cycle_multiplier;
1168 psxRegs.subCycleStep = 0x10000 * cycle_mult / 100;
32631e6a 1169}
1170
ef79bbde
P
1171static void intShutdown() {
1172}
1173
4cc373dd 1174// single step (may do several ops in case of a branch)
4600ba03 1175void execI() {
4cc373dd 1176 execI_(psxMemRLUT, &psxRegs);
ef79bbde
P
1177}
1178
1179R3000Acpu psxInt = {
1180 intInit,
1181 intReset,
1182 intExecute,
1183 intExecuteBlock,
1184 intClear,
943a507a 1185 intNotify,
61ad2a61 1186 intApplyConfig,
ef79bbde
P
1187 intShutdown
1188};