1 /***************************************************************************
2 * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team *
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. *
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. *
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 ***************************************************************************/
21 * PSX assembly interpreter.
24 #include "psxcommon.h"
29 #include "psxinterpreter.h"
32 static int branch = 0;
33 static int branch2 = 0;
36 // These macros are used to assemble the repassembler functions
39 #define debugI() PSXCPU_LOG("%s\n", disR3000AF(psxRegs.code, psxRegs.pc));
49 void (*psxCP2[64])(struct psxCP2Regs *regs);
50 void (*psxCP2BSC[32])();
52 #ifdef ICACHE_EMULATION
55 Use old CPU cache code when the RAM location is updated with new code (affects in-game racing)
57 static u8* ICache_Addr;
58 static u8* ICache_Code;
59 uint32_t *Read_ICache(uint32_t pc)
61 uint32_t pc_bank, pc_offset, pc_cache;
62 uint8_t *IAddr, *ICode;
65 pc_offset = pc & 0xffffff;
66 pc_cache = pc & 0xfff;
72 if (pc_bank == 0x80 || pc_bank == 0x00)
74 if (SWAP32(*(uint32_t *)(IAddr + pc_cache)) == pc_offset)
76 // Cache hit - return last opcode used
77 return (uint32_t *)(ICode + pc_cache);
81 // Cache miss - addresses don't match
82 // - default: 0xffffffff (not init)
84 // cache line is 4 bytes wide
89 *(uint32_t *)(IAddr + pc_cache + 0x0) = SWAP32(pc_offset + 0x0);
90 *(uint32_t *)(IAddr + pc_cache + 0x4) = SWAP32(pc_offset + 0x4);
91 *(uint32_t *)(IAddr + pc_cache + 0x8) = SWAP32(pc_offset + 0x8);
92 *(uint32_t *)(IAddr + pc_cache + 0xc) = SWAP32(pc_offset + 0xc);
95 pc_offset = pc & ~0xf;
96 *(uint32_t *)(ICode + pc_cache + 0x0) = psxMu32ref(pc_offset + 0x0);
97 *(uint32_t *)(ICode + pc_cache + 0x4) = psxMu32ref(pc_offset + 0x4);
98 *(uint32_t *)(ICode + pc_cache + 0x8) = psxMu32ref(pc_offset + 0x8);
99 *(uint32_t *)(ICode + pc_cache + 0xc) = psxMu32ref(pc_offset + 0xc);
104 TODO: Probably should add cached BIOS
107 return (uint32_t *)PSXM(pc);
111 static void delayRead(int reg, u32 bpc) {
114 // SysPrintf("delayRead at %x!\n", psxRegs.pc);
116 rold = psxRegs.GPR.r[reg];
117 psxBSC[psxRegs.code >> 26](); // branch delay load
118 rnew = psxRegs.GPR.r[reg];
124 psxRegs.GPR.r[reg] = rold;
125 execI(); // first branch opcode
126 psxRegs.GPR.r[reg] = rnew;
131 static void delayWrite(int reg, u32 bpc) {
133 /* SysPrintf("delayWrite at %x!\n", psxRegs.pc);
135 SysPrintf("%s\n", disR3000AF(psxRegs.code, psxRegs.pc-4));
136 SysPrintf("%s\n", disR3000AF(PSXMu32(bpc), bpc));*/
138 // no changes from normal behavior
140 psxBSC[psxRegs.code >> 26]();
148 static void delayReadWrite(int reg, u32 bpc) {
150 // SysPrintf("delayReadWrite at %x!\n", psxRegs.pc);
152 // the branch delay load is skipped
160 // this defines shall be used with the tmp
161 // of the next func (instead of _Funct_...)
162 #define _tFunct_ ((tmp ) & 0x3F) // The funct part of the instruction register
163 #define _tRd_ ((tmp >> 11) & 0x1F) // The rd part of the instruction register
164 #define _tRt_ ((tmp >> 16) & 0x1F) // The rt part of the instruction register
165 #define _tRs_ ((tmp >> 21) & 0x1F) // The rs part of the instruction register
166 #define _tSa_ ((tmp >> 6) & 0x1F) // The sa part of the instruction register
168 int psxTestLoadDelay(int reg, u32 tmp) {
169 if (tmp == 0) return 0; // NOP
171 case 0x00: // SPECIAL
174 case 0x02: case 0x03: // SRL/SRA
175 if (_tRd_ == reg && _tRt_ == reg) return 1; else
176 if (_tRt_ == reg) return 2; else
177 if (_tRd_ == reg) return 3;
181 if (_tRs_ == reg) return 2;
184 if (_tRd_ == reg && _tRs_ == reg) return 1; else
185 if (_tRs_ == reg) return 2; else
186 if (_tRd_ == reg) return 3;
189 // SYSCALL/BREAK just a break;
191 case 0x20: case 0x21: case 0x22: case 0x23:
192 case 0x24: case 0x25: case 0x26: case 0x27:
193 case 0x2a: case 0x2b: // ADD/ADDU...
194 case 0x04: case 0x06: case 0x07: // SLLV...
195 if (_tRd_ == reg && (_tRt_ == reg || _tRs_ == reg)) return 1; else
196 if (_tRt_ == reg || _tRs_ == reg) return 2; else
197 if (_tRd_ == reg) return 3;
200 case 0x10: case 0x12: // MFHI/MFLO
201 if (_tRd_ == reg) return 3;
203 case 0x11: case 0x13: // MTHI/MTLO
204 if (_tRs_ == reg) return 2;
207 case 0x18: case 0x19:
208 case 0x1a: case 0x1b: // MULT/DIV...
209 if (_tRt_ == reg || _tRs_ == reg) return 2;
216 case 0x00: case 0x01:
217 case 0x10: case 0x11: // BLTZ/BGEZ...
218 // Xenogears - lbu v0 / beq v0
219 // - no load delay (fixes battle loading)
222 if (_tRs_ == reg) return 2;
227 // J would be just a break;
229 if (31 == reg) return 3;
232 case 0x04: case 0x05: // BEQ/BNE
233 // Xenogears - lbu v0 / beq v0
234 // - no load delay (fixes battle loading)
237 if (_tRs_ == reg || _tRt_ == reg) return 2;
240 case 0x06: case 0x07: // BLEZ/BGTZ
241 // Xenogears - lbu v0 / beq v0
242 // - no load delay (fixes battle loading)
245 if (_tRs_ == reg) return 2;
248 case 0x08: case 0x09: case 0x0a: case 0x0b:
249 case 0x0c: case 0x0d: case 0x0e: // ADDI/ADDIU...
250 if (_tRt_ == reg && _tRs_ == reg) return 1; else
251 if (_tRs_ == reg) return 2; else
252 if (_tRt_ == reg) return 3;
256 if (_tRt_ == reg) return 3;
262 if (_tRt_ == reg) return 3;
265 if (_tRt_ == reg) return 3;
268 if (_tRt_ == reg) return 2;
271 if (_tRt_ == reg) return 2;
282 if (_tRt_ == reg) return 3;
285 if (_tRt_ == reg) return 3;
288 if (_tRt_ == reg) return 2;
291 if (_tRt_ == reg) return 2;
299 case 0x22: case 0x26: // LWL/LWR
300 if (_tRt_ == reg) return 3; else
301 if (_tRs_ == reg) return 2;
304 case 0x20: case 0x21: case 0x23:
305 case 0x24: case 0x25: // LB/LH/LW/LBU/LHU
306 if (_tRt_ == reg && _tRs_ == reg) return 1; else
307 if (_tRs_ == reg) return 2; else
308 if (_tRt_ == reg) return 3;
311 case 0x28: case 0x29: case 0x2a:
312 case 0x2b: case 0x2e: // SB/SH/SWL/SW/SWR
313 if (_tRt_ == reg || _tRs_ == reg) return 2;
316 case 0x32: case 0x3a: // LWC2/SWC2
317 if (_tRs_ == reg) return 2;
324 void psxDelayTest(int reg, u32 bpc) {
328 #ifdef ICACHE_EMULATION
329 if (Config.icache_emulation)
331 code = Read_ICache(psxRegs.pc);
336 code = (u32 *)PSXM(psxRegs.pc);
339 tmp = ((code == NULL) ? 0 : SWAP32(*code));
342 switch (psxTestLoadDelay(reg, tmp)) {
344 delayReadWrite(reg, bpc); return;
346 delayRead(reg, bpc); return;
348 delayWrite(reg, bpc); return;
350 psxBSC[psxRegs.code >> 26]();
358 static u32 psxBranchNoDelay(void) {
362 #ifdef ICACHE_EMULATION
363 if (Config.icache_emulation)
365 code = Read_ICache(psxRegs.pc);
370 code = (u32 *)PSXM(psxRegs.pc);
372 psxRegs.code = ((code == NULL) ? 0 : SWAP32(*code));
374 case 0x00: // SPECIAL
380 if (_Rd_) { _SetLink(_Rd_); }
388 return _BranchTarget_;
391 if (_i32(_rRs_) >= 0)
392 return _BranchTarget_;
395 if (_i32(_rRs_) < 0) {
397 return _BranchTarget_;
401 if (_i32(_rRs_) >= 0) {
403 return _BranchTarget_;
414 if (_i32(_rRs_) == _i32(_rRt_))
415 return _BranchTarget_;
418 if (_i32(_rRs_) != _i32(_rRt_))
419 return _BranchTarget_;
422 if (_i32(_rRs_) <= 0)
423 return _BranchTarget_;
427 return _BranchTarget_;
434 static int psxDelayBranchExec(u32 tar) {
439 psxRegs.cycle += BIAS;
444 static int psxDelayBranchTest(u32 tar1) {
445 u32 tar2, tmp1, tmp2;
447 tar2 = psxBranchNoDelay();
454 * Branch in delay slot:
455 * - execute 1 instruction at tar1
456 * - jump to tar2 (target of branch in delay slot; this branch
457 * has no normal delay slot, instruction at tar1 was fetched instead)
460 tmp1 = psxBranchNoDelay();
461 if (tmp1 == (u32)-1) {
462 return psxDelayBranchExec(tar2);
465 psxRegs.cycle += BIAS;
468 * Got a branch at tar1:
469 * - execute 1 instruction at tar2
470 * - jump to target of that branch (tmp1)
473 tmp2 = psxBranchNoDelay();
474 if (tmp2 == (u32)-1) {
475 return psxDelayBranchExec(tmp1);
478 psxRegs.cycle += BIAS;
481 * Got a branch at tar2:
482 * - execute 1 instruction at tmp1
483 * - jump to target of that branch (tmp2)
486 return psxDelayBranchExec(tmp2);
489 static void doBranch(u32 tar) {
493 branch2 = branch = 1;
496 // check for branch in delay slot
497 if (psxDelayBranchTest(tar))
500 #ifdef ICACHE_EMULATION
501 if (Config.icache_emulation)
503 code = Read_ICache(psxRegs.pc);
508 code = (u32 *)PSXM(psxRegs.pc);
510 psxRegs.code = ((code == NULL) ? 0 : SWAP32(*code));
515 psxRegs.cycle += BIAS;
517 // check for load delay
518 tmp = psxRegs.code >> 26;
524 psxDelayTest(_Rt_, branchPC);
534 psxDelayTest(_Rt_, branchPC);
541 psxDelayTest(_Rt_, branchPC);
544 if (tmp >= 0x20 && tmp <= 0x26) { // LB/LH/LWL/LW/LBU/LHU/LWR
545 psxDelayTest(_Rt_, branchPC);
551 psxBSC[psxRegs.code >> 26]();
554 psxRegs.pc = branchPC;
559 /*********************************************************
560 * Arithmetic with immediate operand *
561 * Format: OP rt, rs, immediate *
562 *********************************************************/
563 void psxADDI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im (Exception on Integer Overflow)
564 void psxADDIU() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im
565 void psxANDI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) & _ImmU_; } // Rt = Rs And Im
566 void psxORI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) | _ImmU_; } // Rt = Rs Or Im
567 void psxXORI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) ^ _ImmU_; } // Rt = Rs Xor Im
568 void psxSLTI() { if (!_Rt_) return; _rRt_ = _i32(_rRs_) < _Imm_ ; } // Rt = Rs < Im (Signed)
569 void psxSLTIU() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) < ((u32)_Imm_); } // Rt = Rs < Im (Unsigned)
571 /*********************************************************
572 * Register arithmetic *
573 * Format: OP rd, rs, rt *
574 *********************************************************/
575 void psxADD() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt (Exception on Integer Overflow)
576 void psxADDU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt
577 void psxSUB() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt (Exception on Integer Overflow)
578 void psxSUBU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt
579 void psxAND() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) & _u32(_rRt_); } // Rd = Rs And Rt
580 void psxOR() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) | _u32(_rRt_); } // Rd = Rs Or Rt
581 void psxXOR() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) ^ _u32(_rRt_); } // Rd = Rs Xor Rt
582 void psxNOR() { if (!_Rd_) return; _rRd_ =~(_u32(_rRs_) | _u32(_rRt_)); }// Rd = Rs Nor Rt
583 void psxSLT() { if (!_Rd_) return; _rRd_ = _i32(_rRs_) < _i32(_rRt_); } // Rd = Rs < Rt (Signed)
584 void psxSLTU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) < _u32(_rRt_); } // Rd = Rs < Rt (Unsigned)
586 /*********************************************************
587 * Register mult/div & Register trap logic *
588 * Format: OP rs, rt *
589 *********************************************************/
592 _i32(_rHi_) = _i32(_rRs_);
593 if (_i32(_rRs_) & 0x80000000) {
596 _i32(_rLo_) = 0xFFFFFFFF;
599 * Notaz said that this was "not needed" for ARM platforms and could slow it down so let's disable for ARM.
600 * This fixes a crash issue that can happen when running Amidog's CPU test.
601 * (It still stays stuck to a black screen but at least it doesn't crash anymore)
603 #if !defined(__arm__) && !defined(__aarch64__)
604 } else if (_i32(_rRs_) == 0x80000000 && _i32(_rRt_) == 0xFFFFFFFF) {
605 _i32(_rLo_) = 0x80000000;
609 _i32(_rLo_) = _i32(_rRs_) / _i32(_rRt_);
610 _i32(_rHi_) = _i32(_rRs_) % _i32(_rRt_);
614 void psxDIV_stall() {
615 psxRegs.muldivBusyCycle = psxRegs.cycle + 37;
621 _rLo_ = _rRs_ / _rRt_;
622 _rHi_ = _rRs_ % _rRt_;
625 _i32(_rLo_) = 0xffffffff;
626 _i32(_rHi_) = _i32(_rRs_);
630 void psxDIVU_stall() {
631 psxRegs.muldivBusyCycle = psxRegs.cycle + 37;
636 u64 res = (s64)((s64)_i32(_rRs_) * (s64)_i32(_rRt_));
638 psxRegs.GPR.n.lo = (u32)(res & 0xffffffff);
639 psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff);
642 void psxMULT_stall() {
643 // approximate, but maybe good enough
645 u32 lz = __builtin_clz(((rs ^ ((s32)rs >> 21)) | 1));
646 u32 c = 7 + (2 - (lz / 11)) * 4;
647 psxRegs.muldivBusyCycle = psxRegs.cycle + c;
652 u64 res = (u64)((u64)_u32(_rRs_) * (u64)_u32(_rRt_));
654 psxRegs.GPR.n.lo = (u32)(res & 0xffffffff);
655 psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff);
658 void psxMULTU_stall() {
659 // approximate, but maybe good enough
660 u32 lz = __builtin_clz(_rRs_ | 1);
661 u32 c = 7 + (2 - (lz / 11)) * 4;
662 psxRegs.muldivBusyCycle = psxRegs.cycle + c;
666 /*********************************************************
667 * Register branch logic *
668 * Format: OP rs, offset *
669 *********************************************************/
670 #define RepZBranchi32(op) if(_i32(_rRs_) op 0) doBranch(_BranchTarget_);
671 #define RepZBranchLinki32(op) { _SetLink(31); if(_i32(_rRs_) op 0) { doBranch(_BranchTarget_); } }
673 void psxBGEZ() { RepZBranchi32(>=) } // Branch if Rs >= 0
674 void psxBGEZAL() { RepZBranchLinki32(>=) } // Branch if Rs >= 0 and link
675 void psxBGTZ() { RepZBranchi32(>) } // Branch if Rs > 0
676 void psxBLEZ() { RepZBranchi32(<=) } // Branch if Rs <= 0
677 void psxBLTZ() { RepZBranchi32(<) } // Branch if Rs < 0
678 void psxBLTZAL() { RepZBranchLinki32(<) } // Branch if Rs < 0 and link
680 /*********************************************************
681 * Shift arithmetic with constant shift *
682 * Format: OP rd, rt, sa *
683 *********************************************************/
684 void psxSLL() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) << _Sa_; } // Rd = Rt << sa
685 void psxSRA() { if (!_Rd_) return; _i32(_rRd_) = _i32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (arithmetic)
686 void psxSRL() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (logical)
688 /*********************************************************
689 * Shift arithmetic with variant register shift *
690 * Format: OP rd, rt, rs *
691 *********************************************************/
692 void psxSLLV() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) << (_u32(_rRs_) & 0x1F); } // Rd = Rt << rs
693 void psxSRAV() { if (!_Rd_) return; _i32(_rRd_) = _i32(_rRt_) >> (_u32(_rRs_) & 0x1F); } // Rd = Rt >> rs (arithmetic)
694 void psxSRLV() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) >> (_u32(_rRs_) & 0x1F); } // Rd = Rt >> rs (logical)
696 /*********************************************************
697 * Load higher 16 bits of the first word in GPR with imm *
698 * Format: OP rt, immediate *
699 *********************************************************/
700 void psxLUI() { if (!_Rt_) return; _u32(_rRt_) = psxRegs.code << 16; } // Upper halfword of Rt = Im
702 /*********************************************************
703 * Move from HI/LO to GPR *
705 *********************************************************/
706 void psxMFHI() { if (!_Rd_) return; _rRd_ = _rHi_; } // Rd = Hi
707 void psxMFLO() { if (!_Rd_) return; _rRd_ = _rLo_; } // Rd = Lo
709 static void mflohiCheckStall(void)
711 u32 left = psxRegs.muldivBusyCycle - psxRegs.cycle;
713 //printf("muldiv stall %u\n", left);
714 psxRegs.cycle = psxRegs.muldivBusyCycle;
718 void psxMFHI_stall() { mflohiCheckStall(); psxMFHI(); }
719 void psxMFLO_stall() { mflohiCheckStall(); psxMFLO(); }
721 /*********************************************************
722 * Move to GPR to HI/LO & Register jump *
724 *********************************************************/
725 void psxMTHI() { _rHi_ = _rRs_; } // Hi = Rs
726 void psxMTLO() { _rLo_ = _rRs_; } // Lo = Rs
728 /*********************************************************
729 * Special purpose instructions *
731 *********************************************************/
734 psxException(0x24, branch);
739 psxException(0x20, branch);
743 // SysPrintf("psxRFE\n");
744 psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status & 0xfffffff0) |
745 ((psxRegs.CP0.n.Status & 0x3c) >> 2);
749 /*********************************************************
750 * Register branch logic *
751 * Format: OP rs, rt, offset *
752 *********************************************************/
753 #define RepBranchi32(op) if(_i32(_rRs_) op _i32(_rRt_)) doBranch(_BranchTarget_);
755 void psxBEQ() { RepBranchi32(==) } // Branch if Rs == Rt
756 void psxBNE() { RepBranchi32(!=) } // Branch if Rs != Rt
758 /*********************************************************
760 * Format: OP target *
761 *********************************************************/
762 void psxJ() { doBranch(_JumpTarget_); }
763 void psxJAL() { _SetLink(31); doBranch(_JumpTarget_); }
765 /*********************************************************
767 * Format: OP rs, rd *
768 *********************************************************/
770 doBranch(_rRs_ & ~3);
775 u32 temp = _u32(_rRs_);
776 if (_Rd_) { _SetLink(_Rd_); }
780 /*********************************************************
781 * Load and store for GPR *
782 * Format: OP rt, offset(base) *
783 *********************************************************/
785 #define _oB_ (_u32(_rRs_) + _Imm_)
789 _i32(_rRt_) = (signed char)psxMemRead8(_oB_);
797 _u32(_rRt_) = psxMemRead8(_oB_);
805 _i32(_rRt_) = (short)psxMemRead16(_oB_);
813 _u32(_rRt_) = psxMemRead16(_oB_);
821 _u32(_rRt_) = psxMemRead32(_oB_);
827 u32 LWL_MASK[4] = { 0xffffff, 0xffff, 0xff, 0 };
828 u32 LWL_SHIFT[4] = { 24, 16, 8, 0 };
832 u32 shift = addr & 3;
833 u32 mem = psxMemRead32(addr & ~3);
836 _u32(_rRt_) = ( _u32(_rRt_) & LWL_MASK[shift]) |
837 ( mem << LWL_SHIFT[shift]);
840 Mem = 1234. Reg = abcd
842 0 4bcd (mem << 24) | (reg & 0x00ffffff)
843 1 34cd (mem << 16) | (reg & 0x0000ffff)
844 2 234d (mem << 8) | (reg & 0x000000ff)
845 3 1234 (mem ) | (reg & 0x00000000)
849 u32 LWR_MASK[4] = { 0, 0xff000000, 0xffff0000, 0xffffff00 };
850 u32 LWR_SHIFT[4] = { 0, 8, 16, 24 };
854 u32 shift = addr & 3;
855 u32 mem = psxMemRead32(addr & ~3);
858 _u32(_rRt_) = ( _u32(_rRt_) & LWR_MASK[shift]) |
859 ( mem >> LWR_SHIFT[shift]);
862 Mem = 1234. Reg = abcd
864 0 1234 (mem ) | (reg & 0x00000000)
865 1 a123 (mem >> 8) | (reg & 0xff000000)
866 2 ab12 (mem >> 16) | (reg & 0xffff0000)
867 3 abc1 (mem >> 24) | (reg & 0xffffff00)
871 void psxSB() { psxMemWrite8 (_oB_, _rRt_ & 0xff); }
872 void psxSH() { psxMemWrite16(_oB_, _rRt_ & 0xffff); }
873 void psxSW() { psxMemWrite32(_oB_, _rRt_); }
875 u32 SWL_MASK[4] = { 0xffffff00, 0xffff0000, 0xff000000, 0 };
876 u32 SWL_SHIFT[4] = { 24, 16, 8, 0 };
880 u32 shift = addr & 3;
881 u32 mem = psxMemRead32(addr & ~3);
883 psxMemWrite32(addr & ~3, (_u32(_rRt_) >> SWL_SHIFT[shift]) |
884 ( mem & SWL_MASK[shift]) );
886 Mem = 1234. Reg = abcd
888 0 123a (reg >> 24) | (mem & 0xffffff00)
889 1 12ab (reg >> 16) | (mem & 0xffff0000)
890 2 1abc (reg >> 8) | (mem & 0xff000000)
891 3 abcd (reg ) | (mem & 0x00000000)
895 u32 SWR_MASK[4] = { 0, 0xff, 0xffff, 0xffffff };
896 u32 SWR_SHIFT[4] = { 0, 8, 16, 24 };
900 u32 shift = addr & 3;
901 u32 mem = psxMemRead32(addr & ~3);
903 psxMemWrite32(addr & ~3, (_u32(_rRt_) << SWR_SHIFT[shift]) |
904 ( mem & SWR_MASK[shift]) );
907 Mem = 1234. Reg = abcd
909 0 abcd (reg ) | (mem & 0x00000000)
910 1 bcd4 (reg << 8) | (mem & 0x000000ff)
911 2 cd34 (reg << 16) | (mem & 0x0000ffff)
912 3 d234 (reg << 24) | (mem & 0x00ffffff)
916 /*********************************************************
917 * Moves between GPR and COPx *
918 * Format: OP rt, fs *
919 *********************************************************/
920 void psxMFC0() { if (!_Rt_) return; _i32(_rRt_) = (int)_rFs_; }
921 void psxCFC0() { if (!_Rt_) return; _i32(_rRt_) = (int)_rFs_; }
923 void psxTestSWInts() {
924 if (psxRegs.CP0.n.Cause & psxRegs.CP0.n.Status & 0x0300 &&
925 psxRegs.CP0.n.Status & 0x1) {
926 psxRegs.CP0.n.Cause &= ~0x7c;
927 psxException(psxRegs.CP0.n.Cause, branch);
931 void MTC0(int reg, u32 val) {
932 // SysPrintf("MTC0 %d: %x\n", reg, val);
935 psxRegs.CP0.r[12] = val;
940 psxRegs.CP0.n.Cause &= ~0x0300;
941 psxRegs.CP0.n.Cause |= val & 0x0300;
946 psxRegs.CP0.r[reg] = val;
951 void psxMTC0() { MTC0(_Rd_, _u32(_rRt_)); }
952 void psxCTC0() { MTC0(_Rd_, _u32(_rRt_)); }
954 /*********************************************************
955 * Unknow instruction (would generate an exception) *
957 *********************************************************/
960 PSXCPU_LOG("psx: Unimplemented op %x\n", psxRegs.code);
977 psxCP2[_Funct_]((struct psxCP2Regs *)&psxRegs.CP2D);
980 void psxCOP2_stall() {
983 psxCP2[f]((struct psxCP2Regs *)&psxRegs.CP2D);
986 void psxBASIC(struct psxCP2Regs *regs) {
991 // psxHLEt[psxRegs.code & 0xffff]();
992 // psxHLEt[psxRegs.code & 0x07](); // HDHOSHY experimental patch
993 uint32_t hleCode = psxRegs.code & 0x03ffffff;
994 if (hleCode >= (sizeof(psxHLEt) / sizeof(psxHLEt[0]))) {
1001 void (*psxBSC[64])() = {
1002 psxSPECIAL, psxREGIMM, psxJ , psxJAL , psxBEQ , psxBNE , psxBLEZ, psxBGTZ,
1003 psxADDI , psxADDIU , psxSLTI, psxSLTIU, psxANDI, psxORI , psxXORI, psxLUI ,
1004 psxCOP0 , psxNULL , psxCOP2, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL,
1005 psxNULL , psxNULL , psxNULL, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL,
1006 psxLB , psxLH , psxLWL , psxLW , psxLBU , psxLHU , psxLWR , psxNULL,
1007 psxSB , psxSH , psxSWL , psxSW , psxNULL, psxNULL, psxSWR , psxNULL,
1008 psxNULL , psxNULL , gteLWC2, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL,
1009 psxNULL , psxNULL , gteSWC2, psxHLE , psxNULL, psxNULL, psxNULL, psxNULL
1013 void (*psxSPC[64])() = {
1014 psxSLL , psxNULL , psxSRL , psxSRA , psxSLLV , psxNULL , psxSRLV, psxSRAV,
1015 psxJR , psxJALR , psxNULL, psxNULL, psxSYSCALL, psxBREAK, psxNULL, psxNULL,
1016 psxMFHI, psxMTHI , psxMFLO, psxMTLO, psxNULL , psxNULL , psxNULL, psxNULL,
1017 psxMULT, psxMULTU, psxDIV , psxDIVU, psxNULL , psxNULL , psxNULL, psxNULL,
1018 psxADD , psxADDU , psxSUB , psxSUBU, psxAND , psxOR , psxXOR , psxNOR ,
1019 psxNULL, psxNULL , psxSLT , psxSLTU, psxNULL , psxNULL , psxNULL, psxNULL,
1020 psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL,
1021 psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL
1024 void (*psxREG[32])() = {
1025 psxBLTZ , psxBGEZ , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
1026 psxNULL , psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
1027 psxBLTZAL, psxBGEZAL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
1028 psxNULL , psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL
1031 void (*psxCP0[32])() = {
1032 psxMFC0, psxNULL, psxCFC0, psxNULL, psxMTC0, psxNULL, psxCTC0, psxNULL,
1033 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
1034 psxRFE , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
1035 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL
1038 void (*psxCP2[64])(struct psxCP2Regs *regs) = {
1039 psxBASIC, gteRTPS , psxNULL , psxNULL, psxNULL, psxNULL , gteNCLIP, psxNULL, // 00
1040 psxNULL , psxNULL , psxNULL , psxNULL, gteOP , psxNULL , psxNULL , psxNULL, // 08
1041 gteDPCS , gteINTPL, gteMVMVA, gteNCDS, gteCDP , psxNULL , gteNCDT , psxNULL, // 10
1042 psxNULL , psxNULL , psxNULL , gteNCCS, gteCC , psxNULL , gteNCS , psxNULL, // 18
1043 gteNCT , psxNULL , psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, // 20
1044 gteSQR , gteDCPL , gteDPCT , psxNULL, psxNULL, gteAVSZ3, gteAVSZ4, psxNULL, // 28
1045 gteRTPT , psxNULL , psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, // 30
1046 psxNULL , psxNULL , psxNULL , psxNULL, psxNULL, gteGPF , gteGPL , gteNCCT // 38
1049 void (*psxCP2BSC[32])() = {
1050 gteMFC2, psxNULL, gteCFC2, psxNULL, gteMTC2, psxNULL, gteCTC2, psxNULL,
1051 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
1052 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL,
1053 psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL
1057 ///////////////////////////////////////////
1059 static int intInit() {
1060 #ifdef ICACHE_EMULATION
1061 /* We have to allocate the icache memory even if
1062 * the user has not enabled it as otherwise it can cause issues.
1066 ICache_Addr = malloc(0x1000);
1075 ICache_Code = malloc(0x1000);
1081 memset(ICache_Addr, 0xff, 0x1000);
1082 memset(ICache_Code, 0xff, 0x1000);
1087 static void intReset() {
1088 #ifdef ICACHE_EMULATION
1089 memset(ICache_Addr, 0xff, 0x1000);
1090 memset(ICache_Code, 0xff, 0x1000);
1100 void intExecuteBlock() {
1102 while (!branch2) execI();
1105 static void intClear(u32 Addr, u32 Size) {
1108 void intNotify (int note, void *data) {
1109 #ifdef ICACHE_EMULATION
1110 /* Gameblabla - Only clear the icache if it's isolated */
1111 if (note == R3000ACPU_NOTIFY_CACHE_ISOLATED)
1113 memset(ICache_Addr, 0xff, 0x1000);
1114 memset(ICache_Code, 0xff, 0x1000);
1119 void applyConfig() {
1120 assert(psxBSC[18] == psxCOP2 || psxBSC[18] == psxCOP2_stall);
1121 assert(psxBSC[50] == gteLWC2 || psxBSC[50] == gteLWC2_stall);
1122 assert(psxBSC[58] == gteSWC2 || psxBSC[58] == gteSWC2_stall);
1123 assert(psxSPC[16] == psxMFHI || psxSPC[16] == psxMFHI_stall);
1124 assert(psxSPC[18] == psxMFLO || psxSPC[18] == psxMFLO_stall);
1125 assert(psxSPC[24] == psxMULT || psxSPC[24] == psxMULT_stall);
1126 assert(psxSPC[25] == psxMULTU || psxSPC[25] == psxMULTU_stall);
1127 assert(psxSPC[26] == psxDIV || psxSPC[26] == psxDIV_stall);
1128 assert(psxSPC[27] == psxDIVU || psxSPC[27] == psxDIVU_stall);
1130 if (Config.DisableStalls) {
1131 psxBSC[18] = psxCOP2;
1132 psxBSC[50] = gteLWC2;
1133 psxBSC[58] = gteSWC2;
1134 psxSPC[16] = psxMFHI;
1135 psxSPC[18] = psxMFLO;
1136 psxSPC[24] = psxMULT;
1137 psxSPC[25] = psxMULTU;
1138 psxSPC[26] = psxDIV;
1139 psxSPC[27] = psxDIVU;
1141 psxBSC[18] = psxCOP2_stall;
1142 psxBSC[50] = gteLWC2_stall;
1143 psxBSC[58] = gteSWC2_stall;
1144 psxSPC[16] = psxMFHI_stall;
1145 psxSPC[18] = psxMFLO_stall;
1146 psxSPC[24] = psxMULT_stall;
1147 psxSPC[25] = psxMULTU_stall;
1148 psxSPC[26] = psxDIV_stall;
1149 psxSPC[27] = psxDIVU_stall;
1153 static void intShutdown() {
1154 #ifdef ICACHE_EMULATION
1169 // interpreter execution
1172 #ifdef ICACHE_EMULATION
1173 if (Config.icache_emulation)
1175 code = Read_ICache(psxRegs.pc);
1180 code = (u32 *)PSXM(psxRegs.pc);
1182 psxRegs.code = ((code == NULL) ? 0 : SWAP32(*code));
1186 if (Config.Debug) ProcessDebug();
1189 psxRegs.cycle += BIAS;
1191 psxBSC[psxRegs.code >> 26]();
1194 R3000Acpu psxInt = {
1200 #ifdef ICACHE_EMULATION