/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - interpreter_r4300.def * * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ DECLARE_JUMP(J, (PC->f.j.inst_index<<2) | ((PCADDR+4) & 0xF0000000), 1, ®[0], 0, 0) DECLARE_JUMP(JAL, (PC->f.j.inst_index<<2) | ((PCADDR+4) & 0xF0000000), 1, ®[31], 0, 0) DECLARE_JUMP(BEQ, PCADDR + (iimmediate+1)*4, irs == irt, ®[0], 0, 0) DECLARE_JUMP(BNE, PCADDR + (iimmediate+1)*4, irs != irt, ®[0], 0, 0) DECLARE_JUMP(BLEZ, PCADDR + (iimmediate+1)*4, irs <= 0, ®[0], 0, 0) DECLARE_JUMP(BGTZ, PCADDR + (iimmediate+1)*4, irs > 0, ®[0], 0, 0) DECLARE_INSTRUCTION(ADDI) { irt32 = irs32 + iimmediate; sign_extended(irt); ADD_TO_PC(1); } DECLARE_INSTRUCTION(ADDIU) { irt32 = irs32 + iimmediate; sign_extended(irt); ADD_TO_PC(1); } DECLARE_INSTRUCTION(SLTI) { if (irs < iimmediate) irt = 1; else irt = 0; ADD_TO_PC(1); } DECLARE_INSTRUCTION(SLTIU) { if ((unsigned long long)irs < (unsigned long long)((long long)iimmediate)) irt = 1; else irt = 0; ADD_TO_PC(1); } DECLARE_INSTRUCTION(ANDI) { irt = irs & (unsigned short)iimmediate; ADD_TO_PC(1); } DECLARE_INSTRUCTION(ORI) { irt = irs | (unsigned short)iimmediate; ADD_TO_PC(1); } DECLARE_INSTRUCTION(XORI) { irt = irs ^ (unsigned short)iimmediate; ADD_TO_PC(1); } DECLARE_INSTRUCTION(LUI) { irt32 = iimmediate << 16; sign_extended(irt); ADD_TO_PC(1); } DECLARE_JUMP(BEQL, PCADDR + (iimmediate+1)*4, irs == irt, ®[0], 1, 0) DECLARE_JUMP(BNEL, PCADDR + (iimmediate+1)*4, irs != irt, ®[0], 1, 0) DECLARE_JUMP(BLEZL, PCADDR + (iimmediate+1)*4, irs <= 0, ®[0], 1, 0) DECLARE_JUMP(BGTZL, PCADDR + (iimmediate+1)*4, irs > 0, ®[0], 1, 0) DECLARE_INSTRUCTION(DADDI) { irt = irs + iimmediate; ADD_TO_PC(1); } DECLARE_INSTRUCTION(DADDIU) { irt = irs + iimmediate; ADD_TO_PC(1); } // TODOXXX refactor the following functions to remove the // lsaddr and lsrpt locals. this may lead to a small speedup too DECLARE_INSTRUCTION(LDL) { const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); long long int *lsrtp = PC->f.i.rt; unsigned long long int word = 0; ADD_TO_PC(1); switch ((lsaddr) & 7) { case 0: address = (unsigned int) lsaddr; rdword = (unsigned long long *) lsrtp; read_dword_in_memory(); break; case 1: address = ((unsigned int) lsaddr) & 0xFFFFFFF8; rdword = &word; read_dword_in_memory(); if(address) *lsrtp = (*lsrtp & 0xFF) | (word << 8); break; case 2: address = ((unsigned int) lsaddr) & 0xFFFFFFF8; rdword = &word; read_dword_in_memory(); if(address) *lsrtp = (*lsrtp & 0xFFFF) | (word << 16); break; case 3: address = ((unsigned int) lsaddr) & 0xFFFFFFF8; rdword = &word; read_dword_in_memory(); if(address) *lsrtp = (*lsrtp & 0xFFFFFF) | (word << 24); break; case 4: address = ((unsigned int) lsaddr) & 0xFFFFFFF8; rdword = &word; read_dword_in_memory(); if(address) *lsrtp = (*lsrtp & 0xFFFFFFFF) | (word << 32); break; case 5: address = ((unsigned int) lsaddr) & 0xFFFFFFF8; rdword = &word; read_dword_in_memory(); if(address) *lsrtp = (*lsrtp & 0xFFFFFFFFFFLL) | (word << 40); break; case 6: address = ((unsigned int) lsaddr) & 0xFFFFFFF8; rdword = &word; read_dword_in_memory(); if(address) *lsrtp = (*lsrtp & 0xFFFFFFFFFFFFLL) | (word << 48); break; case 7: address = ((unsigned int) lsaddr) & 0xFFFFFFF8; rdword = &word; read_dword_in_memory(); if(address) *lsrtp = (*lsrtp & 0xFFFFFFFFFFFFFFLL) | (word << 56); break; } } DECLARE_INSTRUCTION(LDR) { const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); long long int *lsrtp = PC->f.i.rt; unsigned long long int word = 0; ADD_TO_PC(1); switch ((lsaddr) & 7) { case 0: address = ((unsigned int) lsaddr) & 0xFFFFFFF8; rdword = &word; read_dword_in_memory(); if(address) *lsrtp = (*lsrtp & 0xFFFFFFFFFFFFFF00LL) | (word >> 56); break; case 1: address = ((unsigned int) lsaddr) & 0xFFFFFFF8; rdword = &word; read_dword_in_memory(); if(address) *lsrtp = (*lsrtp & 0xFFFFFFFFFFFF0000LL) | (word >> 48); break; case 2: address = ((unsigned int) lsaddr) & 0xFFFFFFF8; rdword = &word; read_dword_in_memory(); if(address) *lsrtp = (*lsrtp & 0xFFFFFFFFFF000000LL) | (word >> 40); break; case 3: address = ((unsigned int) lsaddr) & 0xFFFFFFF8; rdword = &word; read_dword_in_memory(); if(address) *lsrtp = (*lsrtp & 0xFFFFFFFF00000000LL) | (word >> 32); break; case 4: address = ((unsigned int) lsaddr) & 0xFFFFFFF8; rdword = &word; read_dword_in_memory(); if(address) *lsrtp = (*lsrtp & 0xFFFFFF0000000000LL) | (word >> 24); break; case 5: address = ((unsigned int) lsaddr) & 0xFFFFFFF8; rdword = &word; read_dword_in_memory(); if(address) *lsrtp = (*lsrtp & 0xFFFF000000000000LL) | (word >> 16); break; case 6: address = ((unsigned int) lsaddr) & 0xFFFFFFF8; rdword = &word; read_dword_in_memory(); if(address) *lsrtp = (*lsrtp & 0xFF00000000000000LL) | (word >> 8); break; case 7: address = ((unsigned int) lsaddr) & 0xFFFFFFF8; rdword = (unsigned long long *) lsrtp; read_dword_in_memory(); break; } } DECLARE_INSTRUCTION(LB) { const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); long long int *lsrtp = PC->f.i.rt; ADD_TO_PC(1); address = (unsigned int) lsaddr; rdword = (unsigned long long *) lsrtp; read_byte_in_memory(); if (address) sign_extendedb(*lsrtp); } DECLARE_INSTRUCTION(LH) { const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); long long int *lsrtp = PC->f.i.rt; ADD_TO_PC(1); address = (unsigned int) lsaddr; rdword = (unsigned long long *) lsrtp; read_hword_in_memory(); if (address) sign_extendedh(*lsrtp); } DECLARE_INSTRUCTION(LWL) { const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); long long int *lsrtp = PC->f.i.rt; unsigned long long int word = 0; ADD_TO_PC(1); switch ((lsaddr) & 3) { case 0: address = (unsigned int) lsaddr; rdword = (unsigned long long *) lsrtp; read_word_in_memory(); break; case 1: address = ((unsigned int) lsaddr) & 0xFFFFFFFC; rdword = &word; read_word_in_memory(); if(address) *lsrtp = (*lsrtp & 0xFF) | (word << 8); break; case 2: address = ((unsigned int) lsaddr) & 0xFFFFFFFC; rdword = &word; read_word_in_memory(); if(address) *lsrtp = (*lsrtp & 0xFFFF) | (word << 16); break; case 3: address = ((unsigned int) lsaddr) & 0xFFFFFFFC; rdword = &word; read_word_in_memory(); if(address) *lsrtp = (*lsrtp & 0xFFFFFF) | (word << 24); break; } if(address) sign_extended(*lsrtp); } DECLARE_INSTRUCTION(LW) { const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); long long int *lsrtp = PC->f.i.rt; ADD_TO_PC(1); address = (unsigned int) lsaddr; rdword = (unsigned long long *) lsrtp; read_word_in_memory(); if (address) sign_extended(*lsrtp); } DECLARE_INSTRUCTION(LBU) { const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); long long int *lsrtp = PC->f.i.rt; ADD_TO_PC(1); address = (unsigned int) lsaddr; rdword = (unsigned long long *) lsrtp; read_byte_in_memory(); } DECLARE_INSTRUCTION(LHU) { const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); long long int *lsrtp = PC->f.i.rt; ADD_TO_PC(1); address = (unsigned int) lsaddr; rdword = (unsigned long long *) lsrtp; read_hword_in_memory(); } DECLARE_INSTRUCTION(LWR) { const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); long long int *lsrtp = PC->f.i.rt; unsigned long long int word = 0; ADD_TO_PC(1); switch ((lsaddr) & 3) { case 0: address = ((unsigned int) lsaddr) & 0xFFFFFFFC; rdword = &word; read_word_in_memory(); if(address) *lsrtp = (*lsrtp & 0xFFFFFFFFFFFFFF00LL) | ((word >> 24) & 0xFF); break; case 1: address = ((unsigned int) lsaddr) & 0xFFFFFFFC; rdword = &word; read_word_in_memory(); if(address) *lsrtp = (*lsrtp & 0xFFFFFFFFFFFF0000LL) | ((word >> 16) & 0xFFFF); break; case 2: address = ((unsigned int) lsaddr) & 0xFFFFFFFC; rdword = &word; read_word_in_memory(); if(address) *lsrtp = (*lsrtp & 0xFFFFFFFFFF000000LL) | ((word >> 8) & 0XFFFFFF); break; case 3: address = ((unsigned int) lsaddr) & 0xFFFFFFFC; rdword = (unsigned long long *) lsrtp; read_word_in_memory(); if(address) sign_extended(*lsrtp); } } DECLARE_INSTRUCTION(LWU) { const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); long long int *lsrtp = PC->f.i.rt; ADD_TO_PC(1); address = (unsigned int) lsaddr; rdword = (unsigned long long *) lsrtp; read_word_in_memory(); } DECLARE_INSTRUCTION(SB) { const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); long long int *lsrtp = PC->f.i.rt; ADD_TO_PC(1); address = (unsigned int) lsaddr; cpu_byte = (unsigned char)(*lsrtp & 0xFF); write_byte_in_memory(); CHECK_MEMORY(); } DECLARE_INSTRUCTION(SH) { const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); long long int *lsrtp = PC->f.i.rt; ADD_TO_PC(1); address = (unsigned int) lsaddr; hword = (unsigned short)(*lsrtp & 0xFFFF); write_hword_in_memory(); CHECK_MEMORY(); } DECLARE_INSTRUCTION(SWL) { const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); long long int *lsrtp = PC->f.i.rt; unsigned long long int old_word = 0; ADD_TO_PC(1); switch ((lsaddr) & 3) { case 0: address = ((unsigned int) lsaddr) & 0xFFFFFFFC; word = (unsigned int)*lsrtp; write_word_in_memory(); CHECK_MEMORY(); break; case 1: address = ((unsigned int) lsaddr) & 0xFFFFFFFC; rdword = &old_word; read_word_in_memory(); if(address) { word = ((unsigned int)*lsrtp >> 8) | ((unsigned int) old_word & 0xFF000000); write_word_in_memory(); CHECK_MEMORY(); } break; case 2: address = ((unsigned int) lsaddr) & 0xFFFFFFFC; rdword = &old_word; read_word_in_memory(); if(address) { word = ((unsigned int)*lsrtp >> 16) | ((unsigned int) old_word & 0xFFFF0000); write_word_in_memory(); CHECK_MEMORY(); } break; case 3: address = (unsigned int) lsaddr; cpu_byte = (unsigned char)(*lsrtp >> 24); write_byte_in_memory(); CHECK_MEMORY(); break; } } DECLARE_INSTRUCTION(SW) { const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); long long int *lsrtp = PC->f.i.rt; ADD_TO_PC(1); address = (unsigned int) lsaddr; word = (unsigned int)(*lsrtp & 0xFFFFFFFF); write_word_in_memory(); CHECK_MEMORY(); } DECLARE_INSTRUCTION(SDL) { const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); long long int *lsrtp = PC->f.i.rt; unsigned long long int old_word = 0; ADD_TO_PC(1); switch ((lsaddr) & 7) { case 0: address = ((unsigned int) lsaddr) & 0xFFFFFFF8; dword = *lsrtp; write_dword_in_memory(); CHECK_MEMORY(); break; case 1: address = ((unsigned int) lsaddr) & 0xFFFFFFF8; rdword = &old_word; read_dword_in_memory(); if(address) { dword = ((unsigned long long)*lsrtp >> 8)|(old_word & 0xFF00000000000000LL); write_dword_in_memory(); CHECK_MEMORY(); } break; case 2: address = ((unsigned int) lsaddr) & 0xFFFFFFF8; rdword = &old_word; read_dword_in_memory(); if(address) { dword = ((unsigned long long)*lsrtp >> 16)|(old_word & 0xFFFF000000000000LL); write_dword_in_memory(); CHECK_MEMORY(); } break; case 3: address = ((unsigned int) lsaddr) & 0xFFFFFFF8; rdword = &old_word; read_dword_in_memory(); if(address) { dword = ((unsigned long long)*lsrtp >> 24)|(old_word & 0xFFFFFF0000000000LL); write_dword_in_memory(); CHECK_MEMORY(); } break; case 4: address = ((unsigned int) lsaddr) & 0xFFFFFFF8; rdword = &old_word; read_dword_in_memory(); if(address) { dword = ((unsigned long long)*lsrtp >> 32)|(old_word & 0xFFFFFFFF00000000LL); write_dword_in_memory(); CHECK_MEMORY(); } break; case 5: address = ((unsigned int) lsaddr) & 0xFFFFFFF8; rdword = &old_word; read_dword_in_memory(); if(address) { dword = ((unsigned long long)*lsrtp >> 40)|(old_word & 0xFFFFFFFFFF000000LL); write_dword_in_memory(); CHECK_MEMORY(); } break; case 6: address = ((unsigned int) lsaddr) & 0xFFFFFFF8; rdword = &old_word; read_dword_in_memory(); if(address) { dword = ((unsigned long long)*lsrtp >> 48)|(old_word & 0xFFFFFFFFFFFF0000LL); write_dword_in_memory(); CHECK_MEMORY(); } break; case 7: address = ((unsigned int) lsaddr) & 0xFFFFFFF8; rdword = &old_word; read_dword_in_memory(); if(address) { dword = ((unsigned long long)*lsrtp >> 56)|(old_word & 0xFFFFFFFFFFFFFF00LL); write_dword_in_memory(); CHECK_MEMORY(); } break; } } DECLARE_INSTRUCTION(SDR) { const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); long long int *lsrtp = PC->f.i.rt; unsigned long long int old_word = 0; ADD_TO_PC(1); switch ((lsaddr) & 7) { case 0: address = (unsigned int) lsaddr; rdword = &old_word; read_dword_in_memory(); if(address) { dword = (*lsrtp << 56) | (old_word & 0x00FFFFFFFFFFFFFFLL); write_dword_in_memory(); CHECK_MEMORY(); } break; case 1: address = ((unsigned int) lsaddr) & 0xFFFFFFF8; rdword = &old_word; read_dword_in_memory(); if(address) { dword = (*lsrtp << 48) | (old_word & 0x0000FFFFFFFFFFFFLL); write_dword_in_memory(); CHECK_MEMORY(); } break; case 2: address = ((unsigned int) lsaddr) & 0xFFFFFFF8; rdword = &old_word; read_dword_in_memory(); if(address) { dword = (*lsrtp << 40) | (old_word & 0x000000FFFFFFFFFFLL); write_dword_in_memory(); CHECK_MEMORY(); } break; case 3: address = ((unsigned int) lsaddr) & 0xFFFFFFF8; rdword = &old_word; read_dword_in_memory(); if(address) { dword = (*lsrtp << 32) | (old_word & 0x00000000FFFFFFFFLL); write_dword_in_memory(); CHECK_MEMORY(); } break; case 4: address = ((unsigned int) lsaddr) & 0xFFFFFFF8; rdword = &old_word; read_dword_in_memory(); if(address) { dword = (*lsrtp << 24) | (old_word & 0x0000000000FFFFFFLL); write_dword_in_memory(); CHECK_MEMORY(); } break; case 5: address = ((unsigned int) lsaddr) & 0xFFFFFFF8; rdword = &old_word; read_dword_in_memory(); if(address) { dword = (*lsrtp << 16) | (old_word & 0x000000000000FFFFLL); write_dword_in_memory(); CHECK_MEMORY(); } break; case 6: address = ((unsigned int) lsaddr) & 0xFFFFFFF8; rdword = &old_word; read_dword_in_memory(); if(address) { dword = (*lsrtp << 8) | (old_word & 0x00000000000000FFLL); write_dword_in_memory(); CHECK_MEMORY(); } break; case 7: address = ((unsigned int) lsaddr) & 0xFFFFFFF8; dword = *lsrtp; write_dword_in_memory(); CHECK_MEMORY(); break; } } DECLARE_INSTRUCTION(SWR) { const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); long long int *lsrtp = PC->f.i.rt; unsigned long long int old_word = 0; ADD_TO_PC(1); switch ((lsaddr) & 3) { case 0: address = (unsigned int) lsaddr; rdword = &old_word; read_word_in_memory(); if(address) { word = ((unsigned int)*lsrtp << 24) | ((unsigned int) old_word & 0x00FFFFFF); write_word_in_memory(); CHECK_MEMORY(); } break; case 1: address = ((unsigned int) lsaddr) & 0xFFFFFFFC; rdword = &old_word; read_word_in_memory(); if(address) { word = ((unsigned int)*lsrtp << 16) | ((unsigned int) old_word & 0x0000FFFF); write_word_in_memory(); CHECK_MEMORY(); } break; case 2: address = ((unsigned int) lsaddr) & 0xFFFFFFFC; rdword = &old_word; read_word_in_memory(); if(address) { word = ((unsigned int)*lsrtp << 8) | ((unsigned int) old_word & 0x000000FF); write_word_in_memory(); CHECK_MEMORY(); } break; case 3: address = ((unsigned int) lsaddr) & 0xFFFFFFFC; word = (unsigned int)*lsrtp; write_word_in_memory(); CHECK_MEMORY(); break; } } DECLARE_INSTRUCTION(CACHE) { ADD_TO_PC(1); } DECLARE_INSTRUCTION(LL) { const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); long long int *lsrtp = PC->f.i.rt; ADD_TO_PC(1); address = (unsigned int) lsaddr; rdword = (unsigned long long *) lsrtp; read_word_in_memory(); if (address) { sign_extended(*lsrtp); llbit = 1; } } DECLARE_INSTRUCTION(LWC1) { const unsigned char lslfft = lfft; const unsigned int lslfaddr = (unsigned int)(lfoffset + reg[lfbase]); unsigned long long int temp; if (check_cop1_unusable()) return; ADD_TO_PC(1); address = (unsigned int) lslfaddr; rdword = &temp; read_word_in_memory(); if (address) *((int*)reg_cop1_simple[lslfft]) = (int) *rdword; } DECLARE_INSTRUCTION(LDC1) { const unsigned char lslfft = lfft; const unsigned int lslfaddr = (unsigned int)(lfoffset + reg[lfbase]); if (check_cop1_unusable()) return; ADD_TO_PC(1); address = (unsigned int) lslfaddr; rdword = (unsigned long long *)reg_cop1_double[lslfft]; read_dword_in_memory(); } DECLARE_INSTRUCTION(LD) { const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); long long int *lsrtp = PC->f.i.rt; ADD_TO_PC(1); address = (unsigned int) lsaddr; rdword = (unsigned long long *) lsrtp; read_dword_in_memory(); } DECLARE_INSTRUCTION(SC) { const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); long long int *lsrtp = PC->f.i.rt; ADD_TO_PC(1); if(llbit) { address = (unsigned int) lsaddr; word = (unsigned int)(*lsrtp & 0xFFFFFFFF); write_word_in_memory(); CHECK_MEMORY(); llbit = 0; *lsrtp = 1; } else { *lsrtp = 0; } } DECLARE_INSTRUCTION(SWC1) { const unsigned char lslfft = lfft; const unsigned int lslfaddr = (unsigned int)(lfoffset + reg[lfbase]); if (check_cop1_unusable()) return; ADD_TO_PC(1); address = (unsigned int) lslfaddr; word = *((int*)reg_cop1_simple[lslfft]); write_word_in_memory(); CHECK_MEMORY(); } DECLARE_INSTRUCTION(SDC1) { const unsigned char lslfft = lfft; const unsigned int lslfaddr = (unsigned int)(lfoffset + reg[lfbase]); if (check_cop1_unusable()) return; ADD_TO_PC(1); address = (unsigned int) lslfaddr; dword = *((unsigned long long*)reg_cop1_double[lslfft]); write_dword_in_memory(); CHECK_MEMORY(); } DECLARE_INSTRUCTION(SD) { const unsigned int lsaddr = (unsigned int)(iimmediate + irs32); long long int *lsrtp = PC->f.i.rt; ADD_TO_PC(1); address = (unsigned int) lsaddr; dword = *lsrtp; write_dword_in_memory(); CHECK_MEMORY(); }