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