/* * Project 64 - A Nintendo 64 emulator. * * (c) Copyright 2001 zilmar (zilmar@emulation64.com) and * Jabo (jabo@emulation64.com). * * pj64 homepage: www.pj64.net * * Permission to use, copy, modify and distribute Project64 in both binary and * source form, for non-commercial purposes, is hereby granted without fee, * providing that this license information and copyright notice appear with * all copies and any derived work. * * This software is provided 'as-is', without any express or implied * warranty. In no event shall the authors be held liable for any damages * arising from the use of this software. * * Project64 is freeware for PERSONAL USE only. Commercial users should * seek permission of the copyright holders first. Commercial use includes * charging money for Project64 or software derived from Project64. * * The copyright holders request that bug fixes and improvements to the code * should be forwarded to them so if they want them. * */ #include #include #include #include "main.h" #include "cpu.h" #include "usf.h" #ifdef _MSC_VER #define INLINE __forceinline #else #define INLINE inline __attribute__((always_inline)) #endif #include "usf_internal.h" #define ADDRESS_ERROR_EXCEPTION(Address,FromRead) \ DoAddressError(state,state->NextInstruction == JUMP,Address,FromRead);\ state->NextInstruction = JUMP;\ state->JumpToLocation = state->PROGRAM_COUNTER;\ return; //#define TEST_COP1_USABLE_EXCEPTION #define TEST_COP1_USABLE_EXCEPTION \ if ((STATUS_REGISTER & STATUS_CU1) == 0) {\ DoCopUnusableException(state,state->NextInstruction == JUMP,1);\ state->NextInstruction = JUMP;\ state->JumpToLocation = state->PROGRAM_COUNTER;\ return;\ } #define TLB_READ_EXCEPTION(Address) \ DoTLBMiss(state,state->NextInstruction == JUMP,Address);\ state->NextInstruction = JUMP;\ state->JumpToLocation = state->PROGRAM_COUNTER;\ return; /************************* OpCode functions *************************/ void r4300i_J (usf_state_t * state) { state->NextInstruction = DELAY_SLOT; state->JumpToLocation = (state->PROGRAM_COUNTER & 0xF0000000) + (state->Opcode.u.d.target << 2); TestInterpreterJump(state,state->PROGRAM_COUNTER,state->JumpToLocation,0,0); } void r4300i_JAL (usf_state_t * state) { state->NextInstruction = DELAY_SLOT; state->JumpToLocation = (state->PROGRAM_COUNTER & 0xF0000000) + (state->Opcode.u.d.target << 2); TestInterpreterJump(state,state->PROGRAM_COUNTER,state->JumpToLocation,0,0); state->GPR[31].DW= (int32_t)(state->PROGRAM_COUNTER + 8); } void r4300i_BEQ (usf_state_t * state) { state->NextInstruction = DELAY_SLOT; if (state->GPR[state->Opcode.u.b.rs].DW == state->GPR[state->Opcode.u.b.rt].DW) { state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; TestInterpreterJump(state,state->PROGRAM_COUNTER,state->JumpToLocation,state->Opcode.u.b.rs,state->Opcode.u.b.rt); } else { state->JumpToLocation = state->PROGRAM_COUNTER + 8; } } void r4300i_BNE (usf_state_t * state) { state->NextInstruction = DELAY_SLOT; if (state->GPR[state->Opcode.u.b.rs].DW != state->GPR[state->Opcode.u.b.rt].DW) { state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; TestInterpreterJump(state,state->PROGRAM_COUNTER,state->JumpToLocation,state->Opcode.u.b.rs,state->Opcode.u.b.rt); } else { state->JumpToLocation = state->PROGRAM_COUNTER + 8; } } void r4300i_BLEZ (usf_state_t * state) { state->NextInstruction = DELAY_SLOT; if (state->GPR[state->Opcode.u.b.rs].DW <= 0) { state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; TestInterpreterJump(state,state->PROGRAM_COUNTER,state->JumpToLocation,state->Opcode.u.b.rs,0); } else { state->JumpToLocation = state->PROGRAM_COUNTER + 8; } } void r4300i_BGTZ (usf_state_t * state) { state->NextInstruction = DELAY_SLOT; if (state->GPR[state->Opcode.u.b.rs].DW > 0) { state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; TestInterpreterJump(state,state->PROGRAM_COUNTER,state->JumpToLocation,state->Opcode.u.b.rs,0); } else { state->JumpToLocation = state->PROGRAM_COUNTER + 8; } } void r4300i_ADDI (usf_state_t * state) { if (state->Opcode.u.b.rt == 0) { return; } state->GPR[state->Opcode.u.b.rt].DW = (state->GPR[state->Opcode.u.b.rs].W[0] + ((int16_t)state->Opcode.u.c.immediate)); } void r4300i_ADDIU (usf_state_t * state) { state->GPR[state->Opcode.u.b.rt].DW = (state->GPR[state->Opcode.u.b.rs].W[0] + ((int16_t)state->Opcode.u.c.immediate)); } void r4300i_SLTI (usf_state_t * state) { if (state->GPR[state->Opcode.u.b.rs].DW < (int64_t)((int16_t)state->Opcode.u.c.immediate)) { state->GPR[state->Opcode.u.b.rt].DW = 1; } else { state->GPR[state->Opcode.u.b.rt].DW = 0; } } void r4300i_SLTIU (usf_state_t * state) { int32_t imm32 = (int16_t)state->Opcode.u.c.immediate; int64_t imm64; imm64 = imm32; state->GPR[state->Opcode.u.b.rt].DW = state->GPR[state->Opcode.u.b.rs].UDW < (uint64_t)imm64?1:0; } void r4300i_ANDI (usf_state_t * state) { state->GPR[state->Opcode.u.b.rt].DW = state->GPR[state->Opcode.u.b.rs].DW & state->Opcode.u.c.immediate; } void r4300i_ORI (usf_state_t * state) { state->GPR[state->Opcode.u.b.rt].DW = state->GPR[state->Opcode.u.b.rs].DW | state->Opcode.u.c.immediate; } void r4300i_XORI (usf_state_t * state) { state->GPR[state->Opcode.u.b.rt].DW = state->GPR[state->Opcode.u.b.rs].DW ^ state->Opcode.u.c.immediate; } void r4300i_LUI (usf_state_t * state) { if (state->Opcode.u.b.rt == 0) { return; } state->GPR[state->Opcode.u.b.rt].DW = (int32_t)((int16_t)state->Opcode.u.b.offset << 16); } void r4300i_BEQL (usf_state_t * state) { if (state->GPR[state->Opcode.u.b.rs].DW == state->GPR[state->Opcode.u.b.rt].DW) { state->NextInstruction = DELAY_SLOT; state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; TestInterpreterJump(state,state->PROGRAM_COUNTER,state->JumpToLocation,state->Opcode.u.b.rs,state->Opcode.u.b.rt); } else { state->NextInstruction = JUMP; state->JumpToLocation = state->PROGRAM_COUNTER + 8; } } void r4300i_BNEL (usf_state_t * state) { if (state->GPR[state->Opcode.u.b.rs].DW != state->GPR[state->Opcode.u.b.rt].DW) { state->NextInstruction = DELAY_SLOT; state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; TestInterpreterJump(state,state->PROGRAM_COUNTER,state->JumpToLocation,state->Opcode.u.b.rs,state->Opcode.u.b.rt); } else { state->NextInstruction = JUMP; state->JumpToLocation = state->PROGRAM_COUNTER + 8; } } void r4300i_BLEZL (usf_state_t * state) { if (state->GPR[state->Opcode.u.b.rs].DW <= 0) { state->NextInstruction = DELAY_SLOT; state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; TestInterpreterJump(state,state->PROGRAM_COUNTER,state->JumpToLocation,state->Opcode.u.b.rs,0); } else { state->NextInstruction = JUMP; state->JumpToLocation = state->PROGRAM_COUNTER + 8; } } void r4300i_BGTZL (usf_state_t * state) { if (state->GPR[state->Opcode.u.b.rs].DW > 0) { state->NextInstruction = DELAY_SLOT; state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; TestInterpreterJump(state,state->PROGRAM_COUNTER,state->JumpToLocation,state->Opcode.u.b.rs,0); } else { state->NextInstruction = JUMP; state->JumpToLocation = state->PROGRAM_COUNTER + 8; } } void r4300i_DADDIU (usf_state_t * state) { state->GPR[state->Opcode.u.b.rt].DW = state->GPR[state->Opcode.u.b.rs].DW + (int64_t)((int16_t)state->Opcode.u.c.immediate); } uint64_t LDL_MASK[8] = { 0ULL,0xFFULL,0xFFFFULL,0xFFFFFFULL,0xFFFFFFFFULL,0xFFFFFFFFFFULL, 0xFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFULL }; int32_t LDL_SHIFT[8] = { 0, 8, 16, 24, 32, 40, 48, 56 }; void r4300i_LDL (usf_state_t * state) { uint32_t Offset, Address; uint64_t Value; Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; Offset = Address & 7; if (!r4300i_LD_VAddr(state,(Address & ~7),&Value)) { return; } state->GPR[state->Opcode.u.b.rt].DW = state->GPR[state->Opcode.u.b.rt].DW & LDL_MASK[Offset]; state->GPR[state->Opcode.u.b.rt].DW += Value << LDL_SHIFT[Offset]; } uint64_t LDR_MASK[8] = { 0xFFFFFFFFFFFFFF00ULL, 0xFFFFFFFFFFFF0000ULL, 0xFFFFFFFFFF000000ULL, 0xFFFFFFFF00000000ULL, 0xFFFFFF0000000000ULL, 0xFFFF000000000000ULL, 0xFF00000000000000ULL, 0 }; int32_t LDR_SHIFT[8] = { 56, 48, 40, 32, 24, 16, 8, 0 }; void r4300i_LDR (usf_state_t * state) { uint32_t Offset, Address; uint64_t Value; Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; Offset = Address & 7; if (!r4300i_LD_VAddr(state,(Address & ~7),&Value)) { return; } state->GPR[state->Opcode.u.b.rt].DW = state->GPR[state->Opcode.u.b.rt].DW & LDR_MASK[Offset]; state->GPR[state->Opcode.u.b.rt].DW += Value >> LDR_SHIFT[Offset]; } void r4300i_LB (usf_state_t * state) { uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; if (state->Opcode.u.b.rt == 0) { return; } if (!r4300i_LB_VAddr(state,Address,&state->GPR[state->Opcode.u.b.rt].UB[0])) { TLB_READ_EXCEPTION(Address); } else { state->GPR[state->Opcode.u.b.rt].DW = state->GPR[state->Opcode.u.b.rt].B[0]; } } void r4300i_LH (usf_state_t * state) { uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; if ((Address & 1) != 0) { ADDRESS_ERROR_EXCEPTION(Address,1); } if (!r4300i_LH_VAddr(state,Address,&state->GPR[state->Opcode.u.b.rt].UHW[0])) { //if (ShowTLBMisses) { // Too spammy //DisplayError(state, "LH TLB: %X",Address); //} TLB_READ_EXCEPTION(Address); } else { state->GPR[state->Opcode.u.b.rt].DW = state->GPR[state->Opcode.u.b.rt].HW[0]; } } uint32_t LWL_MASK[4] = { 0,0xFF,0xFFFF,0xFFFFFF }; int32_t LWL_SHIFT[4] = { 0, 8, 16, 24}; void r4300i_LWL (usf_state_t * state) { uint32_t Offset, Address, Value; Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; Offset = Address & 3; if (!r4300i_LW_VAddr(state,(Address & ~3),&Value)) { return; } state->GPR[state->Opcode.u.b.rt].DW = (int32_t)(state->GPR[state->Opcode.u.b.rt].W[0] & LWL_MASK[Offset]); state->GPR[state->Opcode.u.b.rt].DW += (int32_t)(Value << LWL_SHIFT[Offset]); } void r4300i_LW (usf_state_t * state) { uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; // if ((Address & 3) != 0) { ADDRESS_ERROR_EXCEPTION(Address,1); } if (state->Opcode.u.b.rt == 0) { return; } if (!r4300i_LW_VAddr(state,Address,&state->GPR[state->Opcode.u.b.rt].UW[0])) { //if (ShowTLBMisses) { //printf("LW TLB: %X",Address); //} TLB_READ_EXCEPTION(Address); } else { state->GPR[state->Opcode.u.b.rt].DW = state->GPR[state->Opcode.u.b.rt].W[0]; } } void r4300i_LBU (usf_state_t * state) { uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; if (!r4300i_LB_VAddr(state,Address,&state->GPR[state->Opcode.u.b.rt].UB[0])) { //if (ShowTLBMisses) { // Too spammy //DisplayError(state, "LBU TLB: %X",Address); //} TLB_READ_EXCEPTION(Address); } else { state->GPR[state->Opcode.u.b.rt].UDW = state->GPR[state->Opcode.u.b.rt].UB[0]; } } void r4300i_LHU (usf_state_t * state) { uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; if ((Address & 1) != 0) { ADDRESS_ERROR_EXCEPTION(Address,1); } if (!r4300i_LH_VAddr(state,Address,&state->GPR[state->Opcode.u.b.rt].UHW[0])) { //if (ShowTLBMisses) { // Too spammy //DisplayError(state, "LHU TLB: %X",Address); //} TLB_READ_EXCEPTION(Address); } else { state->GPR[state->Opcode.u.b.rt].UDW = state->GPR[state->Opcode.u.b.rt].UHW[0]; } } uint32_t LWR_MASK[4] = { 0xFFFFFF00, 0xFFFF0000, 0xFF000000, 0 }; int32_t LWR_SHIFT[4] = { 24, 16 ,8, 0 }; void r4300i_LWR (usf_state_t * state) { uint32_t Offset, Address, Value; Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; Offset = Address & 3; if (!r4300i_LW_VAddr(state,(Address & ~3),&Value)) { return; } state->GPR[state->Opcode.u.b.rt].DW = (int32_t)(state->GPR[state->Opcode.u.b.rt].W[0] & LWR_MASK[Offset]); state->GPR[state->Opcode.u.b.rt].DW += (int32_t)(Value >> LWR_SHIFT[Offset]); } void r4300i_LWU (usf_state_t * state) { uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; if ((Address & 3) != 0) { ADDRESS_ERROR_EXCEPTION(Address,1); } if (state->Opcode.u.b.rt == 0) { return; } if (!r4300i_LW_VAddr(state,Address,&state->GPR[state->Opcode.u.b.rt].UW[0])) { //if (ShowTLBMisses) { // Too spammy //DisplayError(state, "LWU TLB: %X",Address); //} TLB_READ_EXCEPTION(Address); } else { state->GPR[state->Opcode.u.b.rt].UDW = state->GPR[state->Opcode.u.b.rt].UW[0]; } } void r4300i_SB (usf_state_t * state) { uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; if (!r4300i_SB_VAddr(state,Address,state->GPR[state->Opcode.u.b.rt].UB[0])) { } } void r4300i_SH (usf_state_t * state) { uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; if ((Address & 1) != 0) { ADDRESS_ERROR_EXCEPTION(Address,0); } if (!r4300i_SH_VAddr(state,Address,state->GPR[state->Opcode.u.b.rt].UHW[0])) { } } uint32_t SWL_MASK[4] = { 0,0xFF000000,0xFFFF0000,0xFFFFFF00 }; int32_t SWL_SHIFT[4] = { 0, 8, 16, 24 }; void r4300i_SWL (usf_state_t * state) { uint32_t Offset, Address, Value; Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; Offset = Address & 3; if (!r4300i_LW_VAddr(state,(Address & ~3),&Value)) { return; } Value &= SWL_MASK[Offset]; Value += state->GPR[state->Opcode.u.b.rt].UW[0] >> SWL_SHIFT[Offset]; if (!r4300i_SW_VAddr(state,(Address & ~0x03),Value)) { } } void r4300i_SW (usf_state_t * state) { uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; if ((Address & 3) != 0) { ADDRESS_ERROR_EXCEPTION(Address,0); } if (!r4300i_SW_VAddr(state,Address,state->GPR[state->Opcode.u.b.rt].UW[0])) { } //TranslateVaddr(&Address); //if (Address == 0x00090AA0) { // LogMessage("%X: Write %X to %X",state->PROGRAM_COUNTER,state->GPR[state->Opcode.u.b.rt].UW[0],state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset); //} } uint64_t SDL_MASK[8] = { 0,0xFF00000000000000ULL, 0xFFFF000000000000ULL, 0xFFFFFF0000000000ULL, 0xFFFFFFFF00000000ULL, 0xFFFFFFFFFF000000ULL, 0xFFFFFFFFFFFF0000ULL, 0xFFFFFFFFFFFFFF00ULL }; int32_t SDL_SHIFT[8] = { 0, 8, 16, 24, 32, 40, 48, 56 }; void r4300i_SDL (usf_state_t * state) { uint32_t Offset, Address; uint64_t Value; Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; Offset = Address & 7; if (!r4300i_LD_VAddr(state,(Address & ~7),&Value)) { return; } Value &= SDL_MASK[Offset]; Value += state->GPR[state->Opcode.u.b.rt].UDW >> SDL_SHIFT[Offset]; if (!r4300i_SD_VAddr(state,(Address & ~7),Value)) { } } uint64_t SDR_MASK[8] = { 0x00FFFFFFFFFFFFFFULL, 0x0000FFFFFFFFFFFFULL, 0x000000FFFFFFFFFFULL, 0x00000000FFFFFFFFULL, 0x0000000000FFFFFFULL, 0x000000000000FFFFULL, 0x00000000000000FFULL, 0x0000000000000000ULL }; int32_t SDR_SHIFT[8] = { 56,48,40,32,24,16,8,0 }; void r4300i_SDR (usf_state_t * state) { uint32_t Offset, Address; uint64_t Value; Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; Offset = Address & 7; if (!r4300i_LD_VAddr(state,(Address & ~7),&Value)) { return; } Value &= SDR_MASK[Offset]; Value += state->GPR[state->Opcode.u.b.rt].UDW << SDR_SHIFT[Offset]; if (!r4300i_SD_VAddr(state,(Address & ~7),Value)) { } } uint32_t SWR_MASK[4] = { 0x00FFFFFF,0x0000FFFF,0x000000FF,0x00000000 }; int32_t SWR_SHIFT[4] = { 24, 16 , 8, 0 }; void r4300i_SWR (usf_state_t * state) { uint32_t Offset, Address, Value; Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; Offset = Address & 3; if (!r4300i_LW_VAddr(state,(Address & ~3),&Value)) { return; } Value &= SWR_MASK[Offset]; Value += state->GPR[state->Opcode.u.b.rt].UW[0] << SWR_SHIFT[Offset]; if (!r4300i_SW_VAddr(state,(Address & ~0x03),Value)) { } } void r4300i_CACHE (usf_state_t * state) { (void)state; } void r4300i_LL (usf_state_t * state) { uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; uintptr_t ll = 0; if ((Address & 3) != 0) { ADDRESS_ERROR_EXCEPTION(Address,1); } if (state->Opcode.u.b.rt == 0) { return; } if (!r4300i_LW_VAddr(state,Address,&state->GPR[state->Opcode.u.b.rt].UW[0])) { //if (ShowTLBMisses) { // Too spammy //DisplayError(state, "LW TLB: %X",Address); //} TLB_READ_EXCEPTION(Address); } else { state->GPR[state->Opcode.u.b.rt].DW = state->GPR[state->Opcode.u.b.rt].W[0]; } state->LLBit = 1; state->LLAddr = Address; ll = state->LLAddr; TranslateVaddr(state, &ll); state->LLAddr = (uint32_t) ll; } void r4300i_LWC1 (usf_state_t * state) { uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (uint32_t)((int16_t)state->Opcode.u.b.offset); TEST_COP1_USABLE_EXCEPTION if ((Address & 3) != 0) { ADDRESS_ERROR_EXCEPTION(Address,1); } if (!r4300i_LW_VAddr(state,Address,&*(uint32_t *)state->FPRFloatLocation[state->Opcode.u.f.ft])) { //if (ShowTLBMisses) { // Too spammy //DisplayError(state, "LWC1 TLB: %X",Address); //} TLB_READ_EXCEPTION(Address); } } void r4300i_SC (usf_state_t * state) { uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; if ((Address & 3) != 0) { ADDRESS_ERROR_EXCEPTION(Address,0); } if (state->LLBit == 1) { if (!r4300i_SW_VAddr(state,Address,state->GPR[state->Opcode.u.b.rt].UW[0])) { DisplayError(state, "SW TLB: %X",Address); } } state->GPR[state->Opcode.u.b.rt].UW[0] = state->LLBit; } void r4300i_LD (usf_state_t * state) { uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; if ((Address & 7) != 0) { ADDRESS_ERROR_EXCEPTION(Address,1); } if (!r4300i_LD_VAddr(state,Address,&state->GPR[state->Opcode.u.b.rt].UDW)) { } } void r4300i_LDC1 (usf_state_t * state) { uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; TEST_COP1_USABLE_EXCEPTION if ((Address & 7) != 0) { ADDRESS_ERROR_EXCEPTION(Address,1); } if (!r4300i_LD_VAddr(state,Address,&*(uint64_t *)state->FPRDoubleLocation[state->Opcode.u.f.ft])) { } } void r4300i_SWC1 (usf_state_t * state) { uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; TEST_COP1_USABLE_EXCEPTION if ((Address & 3) != 0) { ADDRESS_ERROR_EXCEPTION(Address,0); } if (!r4300i_SW_VAddr(state,Address,*(uint32_t *)state->FPRFloatLocation[state->Opcode.u.f.ft])) { } } void r4300i_SDC1 (usf_state_t * state) { uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; TEST_COP1_USABLE_EXCEPTION if ((Address & 7) != 0) { ADDRESS_ERROR_EXCEPTION(Address,0); } if (!r4300i_SD_VAddr(state,Address,*(int64_t *)state->FPRDoubleLocation[state->Opcode.u.f.ft])) { } } void r4300i_SD (usf_state_t * state) { uint32_t Address = state->GPR[state->Opcode.u.c.base].UW[0] + (int16_t)state->Opcode.u.b.offset; if ((Address & 7) != 0) { ADDRESS_ERROR_EXCEPTION(Address,0); } if (!r4300i_SD_VAddr(state,Address,state->GPR[state->Opcode.u.b.rt].UDW)) { } } /********************** R4300i state->Opcodes: Special **********************/ void r4300i_SPECIAL_SLL (usf_state_t * state) { state->GPR[state->Opcode.u.e.rd].DW = (state->GPR[state->Opcode.u.b.rt].W[0] << state->Opcode.u.e.sa); } void r4300i_SPECIAL_SRL (usf_state_t * state) { state->GPR[state->Opcode.u.e.rd].DW = (int32_t)(state->GPR[state->Opcode.u.b.rt].UW[0] >> state->Opcode.u.e.sa); } void r4300i_SPECIAL_SRA (usf_state_t * state) { state->GPR[state->Opcode.u.e.rd].DW = (state->GPR[state->Opcode.u.b.rt].W[0] >> state->Opcode.u.e.sa); } void r4300i_SPECIAL_SLLV (usf_state_t * state) { if (state->Opcode.u.e.rd == 0) { return; } state->GPR[state->Opcode.u.e.rd].DW = (state->GPR[state->Opcode.u.b.rt].W[0] << (state->GPR[state->Opcode.u.b.rs].UW[0] & 0x1F)); } void r4300i_SPECIAL_SRLV (usf_state_t * state) { state->GPR[state->Opcode.u.e.rd].DW = (int32_t)(state->GPR[state->Opcode.u.b.rt].UW[0] >> (state->GPR[state->Opcode.u.b.rs].UW[0] & 0x1F)); } void r4300i_SPECIAL_SRAV (usf_state_t * state) { state->GPR[state->Opcode.u.e.rd].DW = (state->GPR[state->Opcode.u.b.rt].W[0] >> (state->GPR[state->Opcode.u.b.rs].UW[0] & 0x1F)); } void r4300i_SPECIAL_JR (usf_state_t * state) { state->NextInstruction = DELAY_SLOT; state->JumpToLocation = state->GPR[state->Opcode.u.b.rs].UW[0]; } void r4300i_SPECIAL_JALR (usf_state_t * state) { state->NextInstruction = DELAY_SLOT; state->JumpToLocation = state->GPR[state->Opcode.u.b.rs].UW[0]; state->GPR[state->Opcode.u.e.rd].DW = (int32_t)(state->PROGRAM_COUNTER + 8); } void r4300i_SPECIAL_SYSCALL (usf_state_t * state) { DoSysCallException(state, state->NextInstruction == JUMP); state->NextInstruction = JUMP; state->JumpToLocation = state->PROGRAM_COUNTER; } void r4300i_SPECIAL_BREAK (usf_state_t * state) { *state->WaitMode=1; } void r4300i_SPECIAL_SYNC (usf_state_t * state) { (void)state; } void r4300i_SPECIAL_MFHI (usf_state_t * state) { state->GPR[state->Opcode.u.e.rd].DW = state->HI.DW; } void r4300i_SPECIAL_MTHI (usf_state_t * state) { state->HI.DW = state->GPR[state->Opcode.u.b.rs].DW; } void r4300i_SPECIAL_MFLO (usf_state_t * state) { state->GPR[state->Opcode.u.e.rd].DW = state->LO.DW; } void r4300i_SPECIAL_MTLO (usf_state_t * state) { state->LO.DW = state->GPR[state->Opcode.u.b.rs].DW; } void r4300i_SPECIAL_DSLLV (usf_state_t * state) { state->GPR[state->Opcode.u.e.rd].DW = state->GPR[state->Opcode.u.b.rt].DW << (state->GPR[state->Opcode.u.b.rs].UW[0] & 0x3F); } void r4300i_SPECIAL_DSRLV (usf_state_t * state) { state->GPR[state->Opcode.u.e.rd].UDW = state->GPR[state->Opcode.u.b.rt].UDW >> (state->GPR[state->Opcode.u.b.rs].UW[0] & 0x3F); } void r4300i_SPECIAL_DSRAV (usf_state_t * state) { state->GPR[state->Opcode.u.e.rd].DW = state->GPR[state->Opcode.u.b.rt].DW >> (state->GPR[state->Opcode.u.b.rs].UW[0] & 0x3F); } void r4300i_SPECIAL_MULT (usf_state_t * state) { state->HI.DW = (int64_t)(state->GPR[state->Opcode.u.b.rs].W[0]) * (int64_t)(state->GPR[state->Opcode.u.b.rt].W[0]); state->LO.DW = state->HI.W[0]; state->HI.DW = state->HI.W[1]; } void r4300i_SPECIAL_MULTU (usf_state_t * state) { state->HI.DW = (uint64_t)(state->GPR[state->Opcode.u.b.rs].UW[0]) * (uint64_t)(state->GPR[state->Opcode.u.b.rt].UW[0]); state->LO.DW = state->HI.W[0]; state->HI.DW = state->HI.W[1]; } void r4300i_SPECIAL_DIV (usf_state_t * state) { if ( state->GPR[state->Opcode.u.b.rt].UDW != 0 ) { state->LO.DW = state->GPR[state->Opcode.u.b.rs].W[0] / state->GPR[state->Opcode.u.b.rt].W[0]; state->HI.DW = state->GPR[state->Opcode.u.b.rs].W[0] % state->GPR[state->Opcode.u.b.rt].W[0]; } else { } } void r4300i_SPECIAL_DIVU (usf_state_t * state) { if ( state->GPR[state->Opcode.u.b.rt].UDW != 0 ) { state->LO.DW = (int32_t)(state->GPR[state->Opcode.u.b.rs].UW[0] / state->GPR[state->Opcode.u.b.rt].UW[0]); state->HI.DW = (int32_t)(state->GPR[state->Opcode.u.b.rs].UW[0] % state->GPR[state->Opcode.u.b.rt].UW[0]); } else { } } void r4300i_SPECIAL_DMULT (usf_state_t * state) { MIPS_DWORD Tmp[3]; state->LO.UDW = (uint64_t)state->GPR[state->Opcode.u.b.rs].UW[0] * (uint64_t)state->GPR[state->Opcode.u.b.rt].UW[0]; Tmp[0].UDW = (int64_t)state->GPR[state->Opcode.u.b.rs].W[1] * (int64_t)(uint64_t)state->GPR[state->Opcode.u.b.rt].UW[0]; Tmp[1].UDW = (int64_t)(uint64_t)state->GPR[state->Opcode.u.b.rs].UW[0] * (int64_t)state->GPR[state->Opcode.u.b.rt].W[1]; state->HI.UDW = (int64_t)state->GPR[state->Opcode.u.b.rs].W[1] * (int64_t)state->GPR[state->Opcode.u.b.rt].W[1]; Tmp[2].UDW = (uint64_t)state->LO.UW[1] + (uint64_t)Tmp[0].UW[0] + (uint64_t)Tmp[1].UW[0]; state->LO.UDW += ((uint64_t)Tmp[0].UW[0] + (uint64_t)Tmp[1].UW[0]) << 32; state->HI.UDW += (uint64_t)Tmp[0].W[1] + (uint64_t)Tmp[1].W[1] + Tmp[2].UW[1]; } void r4300i_SPECIAL_DMULTU (usf_state_t * state) { MIPS_DWORD Tmp[3]; state->LO.UDW = (uint64_t)state->GPR[state->Opcode.u.b.rs].UW[0] * (uint64_t)state->GPR[state->Opcode.u.b.rt].UW[0]; Tmp[0].UDW = (uint64_t)state->GPR[state->Opcode.u.b.rs].UW[1] * (uint64_t)state->GPR[state->Opcode.u.b.rt].UW[0]; Tmp[1].UDW = (uint64_t)state->GPR[state->Opcode.u.b.rs].UW[0] * (uint64_t)state->GPR[state->Opcode.u.b.rt].UW[1]; state->HI.UDW = (uint64_t)state->GPR[state->Opcode.u.b.rs].UW[1] * (uint64_t)state->GPR[state->Opcode.u.b.rt].UW[1]; Tmp[2].UDW = (uint64_t)state->LO.UW[1] + (uint64_t)Tmp[0].UW[0] + (uint64_t)Tmp[1].UW[0]; state->LO.UDW += ((uint64_t)Tmp[0].UW[0] + (uint64_t)Tmp[1].UW[0]) << 32; state->HI.UDW += (uint64_t)Tmp[0].UW[1] + (uint64_t)Tmp[1].UW[1] + Tmp[2].UW[1]; } void r4300i_SPECIAL_DDIV (usf_state_t * state) { if ( state->GPR[state->Opcode.u.b.rt].UDW != 0 ) { state->LO.DW = state->GPR[state->Opcode.u.b.rs].DW / state->GPR[state->Opcode.u.b.rt].DW; state->HI.DW = state->GPR[state->Opcode.u.b.rs].DW % state->GPR[state->Opcode.u.b.rt].DW; } else { } } void r4300i_SPECIAL_DDIVU (usf_state_t * state) { if ( state->GPR[state->Opcode.u.b.rt].UDW != 0 ) { state->LO.UDW = state->GPR[state->Opcode.u.b.rs].UDW / state->GPR[state->Opcode.u.b.rt].UDW; state->HI.UDW = state->GPR[state->Opcode.u.b.rs].UDW % state->GPR[state->Opcode.u.b.rt].UDW; } else { } } void r4300i_SPECIAL_ADD (usf_state_t * state) { state->GPR[state->Opcode.u.e.rd].DW = state->GPR[state->Opcode.u.b.rs].W[0] + state->GPR[state->Opcode.u.b.rt].W[0]; } void r4300i_SPECIAL_ADDU (usf_state_t * state) { state->GPR[state->Opcode.u.e.rd].DW = state->GPR[state->Opcode.u.b.rs].W[0] + state->GPR[state->Opcode.u.b.rt].W[0]; } void r4300i_SPECIAL_SUB (usf_state_t * state) { state->GPR[state->Opcode.u.e.rd].DW = state->GPR[state->Opcode.u.b.rs].W[0] - state->GPR[state->Opcode.u.b.rt].W[0]; } void r4300i_SPECIAL_SUBU (usf_state_t * state) { state->GPR[state->Opcode.u.e.rd].DW = state->GPR[state->Opcode.u.b.rs].W[0] - state->GPR[state->Opcode.u.b.rt].W[0]; } void r4300i_SPECIAL_AND (usf_state_t * state) { state->GPR[state->Opcode.u.e.rd].DW = state->GPR[state->Opcode.u.b.rs].DW & state->GPR[state->Opcode.u.b.rt].DW; } void r4300i_SPECIAL_OR (usf_state_t * state) { state->GPR[state->Opcode.u.e.rd].DW = state->GPR[state->Opcode.u.b.rs].DW | state->GPR[state->Opcode.u.b.rt].DW; } void r4300i_SPECIAL_XOR (usf_state_t * state) { state->GPR[state->Opcode.u.e.rd].DW = state->GPR[state->Opcode.u.b.rs].DW ^ state->GPR[state->Opcode.u.b.rt].DW; } void r4300i_SPECIAL_NOR (usf_state_t * state) { state->GPR[state->Opcode.u.e.rd].DW = ~(state->GPR[state->Opcode.u.b.rs].DW | state->GPR[state->Opcode.u.b.rt].DW); } void r4300i_SPECIAL_SLT (usf_state_t * state) { if (state->GPR[state->Opcode.u.b.rs].DW < state->GPR[state->Opcode.u.b.rt].DW) { state->GPR[state->Opcode.u.e.rd].DW = 1; } else { state->GPR[state->Opcode.u.e.rd].DW = 0; } } void r4300i_SPECIAL_SLTU (usf_state_t * state) { if (state->GPR[state->Opcode.u.b.rs].UDW < state->GPR[state->Opcode.u.b.rt].UDW) { state->GPR[state->Opcode.u.e.rd].DW = 1; } else { state->GPR[state->Opcode.u.e.rd].DW = 0; } } void r4300i_SPECIAL_DADD (usf_state_t * state) { state->GPR[state->Opcode.u.e.rd].DW = state->GPR[state->Opcode.u.b.rs].DW + state->GPR[state->Opcode.u.b.rt].DW; } void r4300i_SPECIAL_DADDU (usf_state_t * state) { state->GPR[state->Opcode.u.e.rd].DW = state->GPR[state->Opcode.u.b.rs].DW + state->GPR[state->Opcode.u.b.rt].DW; } void r4300i_SPECIAL_DSUB (usf_state_t * state) { state->GPR[state->Opcode.u.e.rd].DW = state->GPR[state->Opcode.u.b.rs].DW - state->GPR[state->Opcode.u.b.rt].DW; } void r4300i_SPECIAL_DSUBU (usf_state_t * state) { state->GPR[state->Opcode.u.e.rd].DW = state->GPR[state->Opcode.u.b.rs].DW - state->GPR[state->Opcode.u.b.rt].DW; } void r4300i_SPECIAL_TEQ (usf_state_t * state) { if (state->GPR[state->Opcode.u.b.rs].DW == state->GPR[state->Opcode.u.b.rt].DW) { } } void r4300i_SPECIAL_DSLL (usf_state_t * state) { state->GPR[state->Opcode.u.e.rd].DW = (state->GPR[state->Opcode.u.b.rt].DW << state->Opcode.u.e.sa); } void r4300i_SPECIAL_DSRL (usf_state_t * state) { state->GPR[state->Opcode.u.e.rd].UDW = (state->GPR[state->Opcode.u.b.rt].UDW >> state->Opcode.u.e.sa); } void r4300i_SPECIAL_DSRA (usf_state_t * state) { state->GPR[state->Opcode.u.e.rd].DW = (state->GPR[state->Opcode.u.b.rt].DW >> state->Opcode.u.e.sa); } void r4300i_SPECIAL_DSLL32 (usf_state_t * state) { state->GPR[state->Opcode.u.e.rd].DW = (state->GPR[state->Opcode.u.b.rt].DW << (state->Opcode.u.e.sa + 32)); } void r4300i_SPECIAL_DSRL32 (usf_state_t * state) { state->GPR[state->Opcode.u.e.rd].UDW = (state->GPR[state->Opcode.u.b.rt].UDW >> (state->Opcode.u.e.sa + 32)); } void r4300i_SPECIAL_DSRA32 (usf_state_t * state) { state->GPR[state->Opcode.u.e.rd].DW = (state->GPR[state->Opcode.u.b.rt].DW >> (state->Opcode.u.e.sa + 32)); } /********************** R4300i state->Opcodes: RegImm **********************/ void r4300i_REGIMM_BLTZ (usf_state_t * state) { state->NextInstruction = DELAY_SLOT; if (state->GPR[state->Opcode.u.b.rs].DW < 0) { state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; TestInterpreterJump(state,state->PROGRAM_COUNTER,state->JumpToLocation,state->Opcode.u.b.rs,0); } else { state->JumpToLocation = state->PROGRAM_COUNTER + 8; } } void r4300i_REGIMM_BGEZ (usf_state_t * state) { state->NextInstruction = DELAY_SLOT; if (state->GPR[state->Opcode.u.b.rs].DW >= 0) { state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; TestInterpreterJump(state,state->PROGRAM_COUNTER,state->JumpToLocation,state->Opcode.u.b.rs,0); } else { state->JumpToLocation = state->PROGRAM_COUNTER + 8; } } void r4300i_REGIMM_BLTZL (usf_state_t * state) { if (state->GPR[state->Opcode.u.b.rs].DW < 0) { state->NextInstruction = DELAY_SLOT; state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; TestInterpreterJump(state,state->PROGRAM_COUNTER,state->JumpToLocation,state->Opcode.u.b.rs,0); } else { state->NextInstruction = JUMP; state->JumpToLocation = state->PROGRAM_COUNTER + 8; } } void r4300i_REGIMM_BGEZL (usf_state_t * state) { if (state->GPR[state->Opcode.u.b.rs].DW >= 0) { state->NextInstruction = DELAY_SLOT; state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; TestInterpreterJump(state,state->PROGRAM_COUNTER,state->JumpToLocation,state->Opcode.u.b.rs,0); } else { state->NextInstruction = JUMP; state->JumpToLocation = state->PROGRAM_COUNTER + 8; } } void r4300i_REGIMM_BLTZAL (usf_state_t * state) { state->NextInstruction = DELAY_SLOT; if (state->GPR[state->Opcode.u.b.rs].DW < 0) { state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; TestInterpreterJump(state,state->PROGRAM_COUNTER,state->JumpToLocation,state->Opcode.u.b.rs,0); } else { state->JumpToLocation = state->PROGRAM_COUNTER + 8; } state->GPR[31].DW= (int32_t)(state->PROGRAM_COUNTER + 8); } void r4300i_REGIMM_BGEZAL (usf_state_t * state) { state->NextInstruction = DELAY_SLOT; if (state->GPR[state->Opcode.u.b.rs].DW >= 0) { state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; TestInterpreterJump(state,state->PROGRAM_COUNTER,state->JumpToLocation,state->Opcode.u.b.rs,0); } else { state->JumpToLocation = state->PROGRAM_COUNTER + 8; } state->GPR[31].DW = (int32_t)(state->PROGRAM_COUNTER + 8); } /************************** COP0 functions **************************/ void r4300i_COP0_MF (usf_state_t * state) { state->GPR[state->Opcode.u.b.rt].DW = (int32_t)state->CP0[state->Opcode.u.e.rd]; } void r4300i_COP0_MT (usf_state_t * state) { switch (state->Opcode.u.e.rd) { case 0: //Index case 2: //EntryLo0 case 3: //EntryLo1 case 5: //PageMask case 6: //Wired case 10: //Entry Hi case 14: //EPC case 16: //Config case 18: //WatchLo case 19: //WatchHi case 28: //Tag lo case 29: //Tag Hi case 30: //ErrEPC state->CP0[state->Opcode.u.e.rd] = state->GPR[state->Opcode.u.b.rt].UW[0]; break; case 4: //Context state->CP0[state->Opcode.u.e.rd] = state->GPR[state->Opcode.u.b.rt].UW[0] & 0xFF800000; break; case 9: //Count state->CP0[state->Opcode.u.e.rd]= state->GPR[state->Opcode.u.b.rt].UW[0]; ChangeCompareTimer(state); break; case 11: //Compare state->CP0[state->Opcode.u.e.rd] = state->GPR[state->Opcode.u.b.rt].UW[0]; FAKE_CAUSE_REGISTER &= ~CAUSE_IP7; ChangeCompareTimer(state); break; case 12: //Status if ((state->CP0[state->Opcode.u.e.rd] ^ state->GPR[state->Opcode.u.b.rt].UW[0]) != 0) { state->CP0[state->Opcode.u.e.rd] = state->GPR[state->Opcode.u.b.rt].UW[0]; SetFpuLocations(state); } else { state->CP0[state->Opcode.u.e.rd] = state->GPR[state->Opcode.u.b.rt].UW[0]; } if ((state->CP0[state->Opcode.u.e.rd] & 0x18) != 0) { } CheckInterrupts(state); break; case 13: //cause state->CP0[state->Opcode.u.e.rd] &= 0xFFFFCFF; break; default: R4300i_UnknownOpcode(state); } } /************************** COP0 CO functions ***********************/ void r4300i_COP0_CO_TLBR (usf_state_t * state) { TLB_Read(state); } void r4300i_COP0_CO_TLBWI (usf_state_t * state) { WriteTLBEntry(state, INDEX_REGISTER & 0x1F); } void r4300i_COP0_CO_TLBWR (usf_state_t * state) { WriteTLBEntry(state, RANDOM_REGISTER & 0x1F); } void r4300i_COP0_CO_TLBP (usf_state_t * state) { TLB_Probe(state); } void r4300i_COP0_CO_ERET (usf_state_t * state) { state->NextInstruction = JUMP; if ((STATUS_REGISTER & STATUS_ERL) != 0) { state->JumpToLocation = ERROREPC_REGISTER; STATUS_REGISTER &= ~STATUS_ERL; } else { state->JumpToLocation = EPC_REGISTER; STATUS_REGISTER &= ~STATUS_EXL; } state->LLBit = 0; CheckInterrupts(state); } /************************** COP1 functions **************************/ void r4300i_COP1_MF (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION state->GPR[state->Opcode.u.b.rt].DW = *(int32_t *)state->FPRFloatLocation[state->Opcode.u.f.fs]; } void r4300i_COP1_DMF (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION state->GPR[state->Opcode.u.b.rt].DW = *(int64_t *)state->FPRDoubleLocation[state->Opcode.u.f.fs]; } void r4300i_COP1_CF (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION if (state->Opcode.u.f.fs != 31 && state->Opcode.u.f.fs != 0) { return; } state->GPR[state->Opcode.u.b.rt].DW = (int32_t)state->FPCR[state->Opcode.u.f.fs]; } void r4300i_COP1_MT (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION *(int32_t *)state->FPRFloatLocation[state->Opcode.u.f.fs] = state->GPR[state->Opcode.u.b.rt].W[0]; } void r4300i_COP1_DMT (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION *(int64_t *)state->FPRDoubleLocation[state->Opcode.u.f.fs] = state->GPR[state->Opcode.u.b.rt].DW; } void r4300i_COP1_CT (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION if (state->Opcode.u.f.fs == 31) { state->FPCR[state->Opcode.u.f.fs] = state->GPR[state->Opcode.u.b.rt].W[0]; return; } } /************************* COP1: BC1 functions ***********************/ void r4300i_COP1_BCF (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION state->NextInstruction = DELAY_SLOT; if ((state->FPCR[31] & FPCSR_C) == 0) { state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; } else { state->JumpToLocation = state->PROGRAM_COUNTER + 8; } } void r4300i_COP1_BCT (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION state->NextInstruction = DELAY_SLOT; if ((state->FPCR[31] & FPCSR_C) != 0) { state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; } else { state->JumpToLocation = state->PROGRAM_COUNTER + 8; } } void r4300i_COP1_BCFL (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION if ((state->FPCR[31] & FPCSR_C) == 0) { state->NextInstruction = DELAY_SLOT; state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; } else { state->NextInstruction = JUMP; state->JumpToLocation = state->PROGRAM_COUNTER + 8; } } void r4300i_COP1_BCTL (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION if ((state->FPCR[31] & FPCSR_C) != 0) { state->NextInstruction = DELAY_SLOT; state->JumpToLocation = state->PROGRAM_COUNTER + ((int16_t)state->Opcode.u.b.offset << 2) + 4; } else { state->NextInstruction = JUMP; state->JumpToLocation = state->PROGRAM_COUNTER + 8; } } /************************** COP1: S functions ************************/ static INLINE void Float_RoundToInteger32( int32_t * Dest, float * Source ) { *Dest = (int32_t)*Source; } static INLINE void Float_RoundToInteger64( int64_t * Dest, float * Source ) { *Dest = (int64_t)*Source; } void r4300i_COP1_S_ADD (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION *(float *)state->FPRFloatLocation[state->Opcode.u.f.fd] = (*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs] + *(float *)state->FPRFloatLocation[state->Opcode.u.f.ft]); } void r4300i_COP1_S_SUB (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION *(float *)state->FPRFloatLocation[state->Opcode.u.f.fd] = (*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs] - *(float *)state->FPRFloatLocation[state->Opcode.u.f.ft]); } void r4300i_COP1_S_MUL (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION *(float *)state->FPRFloatLocation[state->Opcode.u.f.fd] = (*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs] * *(float *)state->FPRFloatLocation[state->Opcode.u.f.ft]); } void r4300i_COP1_S_DIV (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION *(float *)state->FPRFloatLocation[state->Opcode.u.f.fd] = (*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs] / *(float *)state->FPRFloatLocation[state->Opcode.u.f.ft]); } void r4300i_COP1_S_SQRT (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION *(float *)state->FPRFloatLocation[state->Opcode.u.f.fd] = (float)sqrt(*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs]); } void r4300i_COP1_S_ABS (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION *(float *)state->FPRFloatLocation[state->Opcode.u.f.fd] = (float)fabs(*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs]); } void r4300i_COP1_S_MOV (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION *(float *)state->FPRFloatLocation[state->Opcode.u.f.fd] = *(float *)state->FPRFloatLocation[state->Opcode.u.f.fs]; } void r4300i_COP1_S_NEG (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION *(float *)state->FPRFloatLocation[state->Opcode.u.f.fd] = (*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs] * -1.0f); } void r4300i_COP1_S_TRUNC_L (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION //_controlfp(_RC_CHOP,_MCW_RC); Float_RoundToInteger64(&*(int64_t *)state->FPRDoubleLocation[state->Opcode.u.f.fd],&*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs]); } void r4300i_COP1_S_CEIL_L (usf_state_t * state) { //added by Witten TEST_COP1_USABLE_EXCEPTION //_controlfp(_RC_UP,_MCW_RC); Float_RoundToInteger64(&*(int64_t *)state->FPRDoubleLocation[state->Opcode.u.f.fd],&*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs]); } void r4300i_COP1_S_FLOOR_L (usf_state_t * state) { //added by Witten TEST_COP1_USABLE_EXCEPTION Float_RoundToInteger64(&*(int64_t *)state->FPRDoubleLocation[state->Opcode.u.f.fd],&*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs]); } void r4300i_COP1_S_ROUND_W (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION Float_RoundToInteger32(&*(int32_t *)state->FPRFloatLocation[state->Opcode.u.f.fd],&*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs]); } void r4300i_COP1_S_TRUNC_W (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION //_controlfp(_RC_CHOP,_MCW_RC); Float_RoundToInteger32(&*(int32_t *)state->FPRFloatLocation[state->Opcode.u.f.fd],&*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs]); } void r4300i_COP1_S_CEIL_W (usf_state_t * state) { //added by Witten TEST_COP1_USABLE_EXCEPTION //_controlfp(_RC_UP,_MCW_RC); Float_RoundToInteger32(&*(int32_t *)state->FPRFloatLocation[state->Opcode.u.f.fd],&*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs]); } void r4300i_COP1_S_FLOOR_W (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION Float_RoundToInteger32(&*(int32_t *)state->FPRFloatLocation[state->Opcode.u.f.fd],&*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs]); } void r4300i_COP1_S_CVT_D (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION *(double *)state->FPRDoubleLocation[state->Opcode.u.f.fd] = (double)(*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs]); } void r4300i_COP1_S_CVT_W (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION Float_RoundToInteger32(&*(int32_t *)state->FPRFloatLocation[state->Opcode.u.f.fd],&*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs]); } void r4300i_COP1_S_CVT_L (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION Float_RoundToInteger64(&*(int64_t *)state->FPRDoubleLocation[state->Opcode.u.f.fd],&*(float *)state->FPRFloatLocation[state->Opcode.u.f.fs]); } void r4300i_COP1_S_CMP (usf_state_t * state) { int32_t less, equal, unorded, condition; float Temp0, Temp1; TEST_COP1_USABLE_EXCEPTION Temp0 = *(float *)state->FPRFloatLocation[state->Opcode.u.f.fs]; Temp1 = *(float *)state->FPRFloatLocation[state->Opcode.u.f.ft]; if(0) { //if (_isnan(Temp0) || _isnan(Temp1)) { less = 0; equal = 0; unorded = 1; if ((state->Opcode.u.e.funct & 8) != 0) { } } else { less = Temp0 < Temp1; equal = Temp0 == Temp1; unorded = 0; } condition = ((state->Opcode.u.e.funct & 4) && less) | ((state->Opcode.u.e.funct & 2) && equal) | ((state->Opcode.u.e.funct & 1) && unorded); if (condition) { state->FPCR[31] |= FPCSR_C; } else { state->FPCR[31] &= ~FPCSR_C; } } /************************** COP1: D functions ************************/ static INLINE void Double_RoundToInteger32( int32_t * Dest, double * Source ) { *Dest = (int32_t)*Source; } static INLINE void Double_RoundToInteger64( int64_t * Dest, double * Source ) { *Dest = (int64_t)*Source; } void r4300i_COP1_D_ADD (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION *(double *)state->FPRDoubleLocation[state->Opcode.u.f.fd] = *(double *)state->FPRDoubleLocation[state->Opcode.u.f.fs] + *(double *)state->FPRDoubleLocation[state->Opcode.u.f.ft]; } void r4300i_COP1_D_SUB (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION *(double *)state->FPRDoubleLocation[state->Opcode.u.f.fd] = *(double *)state->FPRDoubleLocation[state->Opcode.u.f.fs] - *(double *)state->FPRDoubleLocation[state->Opcode.u.f.ft]; } void r4300i_COP1_D_MUL (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION *(double *)state->FPRDoubleLocation[state->Opcode.u.f.fd] = *(double *)state->FPRDoubleLocation[state->Opcode.u.f.fs] * *(double *)state->FPRDoubleLocation[state->Opcode.u.f.ft]; } void r4300i_COP1_D_DIV (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION *(double *)state->FPRDoubleLocation[state->Opcode.u.f.fd] = *(double *)state->FPRDoubleLocation[state->Opcode.u.f.fs] / *(double *)state->FPRDoubleLocation[state->Opcode.u.f.ft]; } void r4300i_COP1_D_SQRT (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION *(double *)state->FPRDoubleLocation[state->Opcode.u.f.fd] = (double)sqrt(*(double *)state->FPRDoubleLocation[state->Opcode.u.f.fs]); } void r4300i_COP1_D_ABS (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION *(double *)state->FPRDoubleLocation[state->Opcode.u.f.fd] = fabs(*(double *)state->FPRDoubleLocation[state->Opcode.u.f.fs]); } void r4300i_COP1_D_MOV (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION *(int64_t *)state->FPRDoubleLocation[state->Opcode.u.f.fd] = *(int64_t *)state->FPRDoubleLocation[state->Opcode.u.f.fs]; } void r4300i_COP1_D_NEG (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION *(double *)state->FPRDoubleLocation[state->Opcode.u.f.fd] = (*(double *)state->FPRDoubleLocation[state->Opcode.u.f.fs] * -1.0); } void r4300i_COP1_D_TRUNC_L (usf_state_t * state) { //added by Witten TEST_COP1_USABLE_EXCEPTION Double_RoundToInteger64(&*(int64_t *)state->FPRFloatLocation[state->Opcode.u.f.fd],&*(double *)state->FPRDoubleLocation[state->Opcode.u.f.fs] ); } void r4300i_COP1_D_CEIL_L (usf_state_t * state) { //added by Witten TEST_COP1_USABLE_EXCEPTION Double_RoundToInteger64(&*(int64_t *)state->FPRFloatLocation[state->Opcode.u.f.fd],&*(double *)state->FPRDoubleLocation[state->Opcode.u.f.fs] ); } void r4300i_COP1_D_FLOOR_L (usf_state_t * state) { //added by Witten TEST_COP1_USABLE_EXCEPTION Double_RoundToInteger64(&*(int64_t *)state->FPRDoubleLocation[state->Opcode.u.f.fd],&*(double *)state->FPRFloatLocation[state->Opcode.u.f.fs]); } void r4300i_COP1_D_ROUND_W (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION Double_RoundToInteger32(&*(int32_t *)state->FPRFloatLocation[state->Opcode.u.f.fd],&*(double *)state->FPRDoubleLocation[state->Opcode.u.f.fs] ); } void r4300i_COP1_D_TRUNC_W (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION Double_RoundToInteger32(&*(int32_t *)state->FPRFloatLocation[state->Opcode.u.f.fd],&*(double *)state->FPRDoubleLocation[state->Opcode.u.f.fs] ); } void r4300i_COP1_D_CEIL_W (usf_state_t * state) { //added by Witten TEST_COP1_USABLE_EXCEPTION Double_RoundToInteger32(&*(int32_t *)state->FPRFloatLocation[state->Opcode.u.f.fd],&*(double *)state->FPRDoubleLocation[state->Opcode.u.f.fs] ); } void r4300i_COP1_D_FLOOR_W (usf_state_t * state) { //added by Witten TEST_COP1_USABLE_EXCEPTION Double_RoundToInteger32(&*(int32_t *)state->FPRDoubleLocation[state->Opcode.u.f.fd],&*(double *)state->FPRFloatLocation[state->Opcode.u.f.fs]); } void r4300i_COP1_D_CVT_S (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION *(float *)state->FPRFloatLocation[state->Opcode.u.f.fd] = (float)*(double *)state->FPRDoubleLocation[state->Opcode.u.f.fs]; } void r4300i_COP1_D_CVT_W (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION Double_RoundToInteger32(&*(int32_t *)state->FPRFloatLocation[state->Opcode.u.f.fd],&*(double *)state->FPRDoubleLocation[state->Opcode.u.f.fs] ); } void r4300i_COP1_D_CVT_L (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION Double_RoundToInteger64(&*(int64_t *)state->FPRDoubleLocation[state->Opcode.u.f.fd],&*(double *)state->FPRDoubleLocation[state->Opcode.u.f.fs]); } void r4300i_COP1_D_CMP (usf_state_t * state) { int32_t less, equal, unorded, condition; MIPS_DWORD Temp0, Temp1; TEST_COP1_USABLE_EXCEPTION Temp0.DW = *(int64_t *)state->FPRDoubleLocation[state->Opcode.u.f.fs]; Temp1.DW = *(int64_t *)state->FPRDoubleLocation[state->Opcode.u.f.ft]; if(0) { //if (_isnan(Temp0.D) || _isnan(Temp1.D)) { less = 0; equal = 0; unorded = 1; if ((state->Opcode.u.e.funct & 8) != 0) { } } else { less = Temp0.D < Temp1.D; equal = Temp0.D == Temp1.D; unorded = 0; } condition = ((state->Opcode.u.e.funct & 4) && less) | ((state->Opcode.u.e.funct & 2) && equal) | ((state->Opcode.u.e.funct & 1) && unorded); if (condition) { state->FPCR[31] |= FPCSR_C; } else { state->FPCR[31] &= ~FPCSR_C; } } /************************** COP1: W functions ************************/ void r4300i_COP1_W_CVT_S (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION *(float *)state->FPRFloatLocation[state->Opcode.u.f.fd] = (float)*(int32_t *)state->FPRFloatLocation[state->Opcode.u.f.fs]; } void r4300i_COP1_W_CVT_D (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION *(double *)state->FPRDoubleLocation[state->Opcode.u.f.fd] = (double)*(int32_t *)state->FPRFloatLocation[state->Opcode.u.f.fs]; } /************************** COP1: L functions ************************/ void r4300i_COP1_L_CVT_S (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION *(float *)state->FPRFloatLocation[state->Opcode.u.f.fd] = (float)*(int64_t *)state->FPRDoubleLocation[state->Opcode.u.f.fs]; } void r4300i_COP1_L_CVT_D (usf_state_t * state) { TEST_COP1_USABLE_EXCEPTION *(double *)state->FPRDoubleLocation[state->Opcode.u.f.fd] = (double)*(int64_t *)state->FPRDoubleLocation[state->Opcode.u.f.fs]; } /************************** Other functions **************************/ void R4300i_UnknownOpcode (usf_state_t * state) { DisplayError(state, "Unknown R4300i Opcode.\tPC:%08x\tOp:%08x\n", state->PROGRAM_COUNTER,state->Opcode.u.Hex); StopEmulation(state); }