1629 lines
46 KiB
C
1629 lines
46 KiB
C
/*
|
|
* 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 <windows.h>
|
|
#include <stdio.h>
|
|
#include <math.h>
|
|
#include <float.h>
|
|
#include "main.h"
|
|
#include "cpu.h"
|
|
#include "debugger.h"
|
|
|
|
int RoundingModel = _RC_NEAR;
|
|
|
|
#define ADDRESS_ERROR_EXCEPTION(Address,FromRead) \
|
|
DoAddressError(NextInstruction == JUMP,Address,FromRead);\
|
|
NextInstruction = JUMP;\
|
|
JumpToLocation = PROGRAM_COUNTER;\
|
|
return;
|
|
|
|
//#define TEST_COP1_USABLE_EXCEPTION
|
|
#define TEST_COP1_USABLE_EXCEPTION \
|
|
if ((STATUS_REGISTER & STATUS_CU1) == 0) {\
|
|
DoCopUnusableException(NextInstruction == JUMP,1);\
|
|
NextInstruction = JUMP;\
|
|
JumpToLocation = PROGRAM_COUNTER;\
|
|
return;\
|
|
}
|
|
|
|
#define TLB_READ_EXCEPTION(Address) \
|
|
DoTLBMiss(NextInstruction == JUMP,Address);\
|
|
NextInstruction = JUMP;\
|
|
JumpToLocation = PROGRAM_COUNTER;\
|
|
return;
|
|
|
|
/************************* OpCode functions *************************/
|
|
void _fastcall r4300i_J (void) {
|
|
NextInstruction = DELAY_SLOT;
|
|
JumpToLocation = (PROGRAM_COUNTER & 0xF0000000) + (Opcode.target << 2);
|
|
TestInterpreterJump(PROGRAM_COUNTER,JumpToLocation,0,0);
|
|
}
|
|
|
|
void _fastcall r4300i_JAL (void) {
|
|
NextInstruction = DELAY_SLOT;
|
|
JumpToLocation = (PROGRAM_COUNTER & 0xF0000000) + (Opcode.target << 2);
|
|
TestInterpreterJump(PROGRAM_COUNTER,JumpToLocation,0,0);
|
|
GPR[31].DW= (long)(PROGRAM_COUNTER + 8);
|
|
}
|
|
|
|
void _fastcall r4300i_BEQ (void) {
|
|
NextInstruction = DELAY_SLOT;
|
|
if (GPR[Opcode.rs].DW == GPR[Opcode.rt].DW) {
|
|
JumpToLocation = PROGRAM_COUNTER + ((short)Opcode.offset << 2) + 4;
|
|
TestInterpreterJump(PROGRAM_COUNTER,JumpToLocation,Opcode.rs,Opcode.rt);
|
|
} else {
|
|
JumpToLocation = PROGRAM_COUNTER + 8;
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_BNE (void) {
|
|
NextInstruction = DELAY_SLOT;
|
|
if (GPR[Opcode.rs].DW != GPR[Opcode.rt].DW) {
|
|
JumpToLocation = PROGRAM_COUNTER + ((short)Opcode.offset << 2) + 4;
|
|
TestInterpreterJump(PROGRAM_COUNTER,JumpToLocation,Opcode.rs,Opcode.rt);
|
|
} else {
|
|
JumpToLocation = PROGRAM_COUNTER + 8;
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_BLEZ (void) {
|
|
NextInstruction = DELAY_SLOT;
|
|
if (GPR[Opcode.rs].DW <= 0) {
|
|
JumpToLocation = PROGRAM_COUNTER + ((short)Opcode.offset << 2) + 4;
|
|
TestInterpreterJump(PROGRAM_COUNTER,JumpToLocation,Opcode.rs,0);
|
|
} else {
|
|
JumpToLocation = PROGRAM_COUNTER + 8;
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_BGTZ (void) {
|
|
NextInstruction = DELAY_SLOT;
|
|
if (GPR[Opcode.rs].DW > 0) {
|
|
JumpToLocation = PROGRAM_COUNTER + ((short)Opcode.offset << 2) + 4;
|
|
TestInterpreterJump(PROGRAM_COUNTER,JumpToLocation,Opcode.rs,0);
|
|
} else {
|
|
JumpToLocation = PROGRAM_COUNTER + 8;
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_ADDI (void) {
|
|
#ifdef Interpreter_StackTest
|
|
if (Opcode.rs == 29 && Opcode.rt == 29) {
|
|
StackValue += (short)Opcode.immediate;
|
|
}
|
|
#endif
|
|
if (Opcode.rt == 0) { return; }
|
|
GPR[Opcode.rt].DW = (GPR[Opcode.rs].W[0] + ((short)Opcode.immediate));
|
|
#ifdef Interpreter_StackTest
|
|
if (Opcode.rt == 29 && Opcode.rs != 29) {
|
|
StackValue = GPR[Opcode.rt].W[0];
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void _fastcall r4300i_ADDIU (void) {
|
|
#ifdef Interpreter_StackTest
|
|
if (Opcode.rs == 29 && Opcode.rt == 29) {
|
|
StackValue += (short)Opcode.immediate;
|
|
}
|
|
#endif
|
|
GPR[Opcode.rt].DW = (GPR[Opcode.rs].W[0] + ((short)Opcode.immediate));
|
|
#ifdef Interpreter_StackTest
|
|
if (Opcode.rt == 29 && Opcode.rs != 29) {
|
|
StackValue = GPR[Opcode.rt].W[0];
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void _fastcall r4300i_SLTI (void) {
|
|
if (GPR[Opcode.rs].DW < (_int64)((short)Opcode.immediate)) {
|
|
GPR[Opcode.rt].DW = 1;
|
|
} else {
|
|
GPR[Opcode.rt].DW = 0;
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_SLTIU (void) {
|
|
int imm32 = (short)Opcode.immediate;
|
|
__int64 imm64;
|
|
|
|
imm64 = imm32;
|
|
GPR[Opcode.rt].DW = GPR[Opcode.rs].UDW < (unsigned __int64)imm64?1:0;
|
|
}
|
|
|
|
void _fastcall r4300i_ANDI (void) {
|
|
GPR[Opcode.rt].DW = GPR[Opcode.rs].DW & Opcode.immediate;
|
|
}
|
|
|
|
void _fastcall r4300i_ORI (void) {
|
|
GPR[Opcode.rt].DW = GPR[Opcode.rs].DW | Opcode.immediate;
|
|
}
|
|
|
|
void _fastcall r4300i_XORI (void) {
|
|
GPR[Opcode.rt].DW = GPR[Opcode.rs].DW ^ Opcode.immediate;
|
|
}
|
|
|
|
void _fastcall r4300i_LUI (void) {
|
|
if (Opcode.rt == 0) { return; }
|
|
GPR[Opcode.rt].DW = (long)((short)Opcode.offset << 16);
|
|
#ifdef Interpreter_StackTest
|
|
if (Opcode.rt == 29) {
|
|
StackValue = GPR[Opcode.rt].W[0];
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void _fastcall r4300i_BEQL (void) {
|
|
if (GPR[Opcode.rs].DW == GPR[Opcode.rt].DW) {
|
|
NextInstruction = DELAY_SLOT;
|
|
JumpToLocation = PROGRAM_COUNTER + ((short)Opcode.offset << 2) + 4;
|
|
TestInterpreterJump(PROGRAM_COUNTER,JumpToLocation,Opcode.rs,Opcode.rt);
|
|
} else {
|
|
NextInstruction = JUMP;
|
|
JumpToLocation = PROGRAM_COUNTER + 8;
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_BNEL (void) {
|
|
if (GPR[Opcode.rs].DW != GPR[Opcode.rt].DW) {
|
|
NextInstruction = DELAY_SLOT;
|
|
JumpToLocation = PROGRAM_COUNTER + ((short)Opcode.offset << 2) + 4;
|
|
TestInterpreterJump(PROGRAM_COUNTER,JumpToLocation,Opcode.rs,Opcode.rt);
|
|
} else {
|
|
NextInstruction = JUMP;
|
|
JumpToLocation = PROGRAM_COUNTER + 8;
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_BLEZL (void) {
|
|
if (GPR[Opcode.rs].DW <= 0) {
|
|
NextInstruction = DELAY_SLOT;
|
|
JumpToLocation = PROGRAM_COUNTER + ((short)Opcode.offset << 2) + 4;
|
|
TestInterpreterJump(PROGRAM_COUNTER,JumpToLocation,Opcode.rs,0);
|
|
} else {
|
|
NextInstruction = JUMP;
|
|
JumpToLocation = PROGRAM_COUNTER + 8;
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_BGTZL (void) {
|
|
if (GPR[Opcode.rs].DW > 0) {
|
|
NextInstruction = DELAY_SLOT;
|
|
JumpToLocation = PROGRAM_COUNTER + ((short)Opcode.offset << 2) + 4;
|
|
TestInterpreterJump(PROGRAM_COUNTER,JumpToLocation,Opcode.rs,0);
|
|
} else {
|
|
NextInstruction = JUMP;
|
|
JumpToLocation = PROGRAM_COUNTER + 8;
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_DADDIU (void) {
|
|
GPR[Opcode.rt].DW = GPR[Opcode.rs].DW + (_int64)((short)Opcode.immediate);
|
|
}
|
|
|
|
QWORD LDL_MASK[8] = { 0,0xFF,0xFFFF,0xFFFFFF,0xFFFFFFFF,0xFFFFFFFFFF,
|
|
0xFFFFFFFFFFFF, 0xFFFFFFFFFFFFFF };
|
|
int LDL_SHIFT[8] = { 0, 8, 16, 24, 32, 40, 48, 56 };
|
|
|
|
void _fastcall r4300i_LDL (void) {
|
|
DWORD Offset, Address;
|
|
QWORD Value;
|
|
|
|
Address = GPR[Opcode.base].UW[0] + (short)Opcode.offset;
|
|
Offset = Address & 7;
|
|
|
|
if (!r4300i_LD_VAddr((Address & ~7),&Value)) {
|
|
#ifndef EXTERNAL_RELEASE
|
|
DisplayError("LDL TLB: %X",Address);
|
|
#endif
|
|
return;
|
|
}
|
|
GPR[Opcode.rt].DW = GPR[Opcode.rt].DW & LDL_MASK[Offset];
|
|
GPR[Opcode.rt].DW += Value << LDL_SHIFT[Offset];
|
|
}
|
|
|
|
QWORD LDR_MASK[8] = { 0xFFFFFFFFFFFFFF00, 0xFFFFFFFFFFFF0000,
|
|
0xFFFFFFFFFF000000, 0xFFFFFFFF00000000,
|
|
0xFFFFFF0000000000, 0xFFFF000000000000,
|
|
0xFF00000000000000, 0 };
|
|
int LDR_SHIFT[8] = { 56, 48, 40, 32, 24, 16, 8, 0 };
|
|
|
|
void _fastcall r4300i_LDR (void) {
|
|
DWORD Offset, Address;
|
|
QWORD Value;
|
|
|
|
Address = GPR[Opcode.base].UW[0] + (short)Opcode.offset;
|
|
Offset = Address & 7;
|
|
|
|
if (!r4300i_LD_VAddr((Address & ~7),&Value)) {
|
|
#ifndef EXTERNAL_RELEASE
|
|
DisplayError("LDL TLB: %X",Address);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
GPR[Opcode.rt].DW = GPR[Opcode.rt].DW & LDR_MASK[Offset];
|
|
GPR[Opcode.rt].DW += Value >> LDR_SHIFT[Offset];
|
|
|
|
}
|
|
|
|
void _fastcall r4300i_LB (void) {
|
|
DWORD Address = GPR[Opcode.base].UW[0] + (short)Opcode.offset;
|
|
if (Opcode.rt == 0) { return; }
|
|
if (!r4300i_LB_VAddr(Address,&GPR[Opcode.rt].UB[0])) {
|
|
if (ShowTLBMisses) {
|
|
#ifndef EXTERNAL_RELEASE
|
|
DisplayError("LB TLB: %X",Address);
|
|
#endif
|
|
}
|
|
TLB_READ_EXCEPTION(Address);
|
|
} else {
|
|
GPR[Opcode.rt].DW = GPR[Opcode.rt].B[0];
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_LH (void) {
|
|
DWORD Address = GPR[Opcode.base].UW[0] + (short)Opcode.offset;
|
|
if ((Address & 1) != 0) { ADDRESS_ERROR_EXCEPTION(Address,TRUE); }
|
|
if (!r4300i_LH_VAddr(Address,&GPR[Opcode.rt].UHW[0])) {
|
|
if (ShowTLBMisses) {
|
|
DisplayError("LH TLB: %X",Address);
|
|
}
|
|
TLB_READ_EXCEPTION(Address);
|
|
} else {
|
|
GPR[Opcode.rt].DW = GPR[Opcode.rt].HW[0];
|
|
}
|
|
}
|
|
|
|
DWORD LWL_MASK[4] = { 0,0xFF,0xFFFF,0xFFFFFF };
|
|
int LWL_SHIFT[4] = { 0, 8, 16, 24};
|
|
|
|
void _fastcall r4300i_LWL (void) {
|
|
DWORD Offset, Address, Value;
|
|
|
|
Address = GPR[Opcode.base].UW[0] + (short)Opcode.offset;
|
|
Offset = Address & 3;
|
|
|
|
if (!r4300i_LW_VAddr((Address & ~3),&Value)) {
|
|
#ifndef EXTERNAL_RELEASE
|
|
DisplayError("LDL TLB: %X",Address);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
GPR[Opcode.rt].DW = (int)(GPR[Opcode.rt].W[0] & LWL_MASK[Offset]);
|
|
GPR[Opcode.rt].DW += (int)(Value << LWL_SHIFT[Offset]);
|
|
}
|
|
|
|
void _fastcall r4300i_LW (void) {
|
|
DWORD Address = GPR[Opcode.base].UW[0] + (short)Opcode.offset;
|
|
if ((Address & 3) != 0) { ADDRESS_ERROR_EXCEPTION(Address,TRUE); }
|
|
|
|
#if (!defined(EXTERNAL_RELEASE))
|
|
Log_LW(PROGRAM_COUNTER,Address);
|
|
#endif
|
|
if (Opcode.rt == 0) { return; }
|
|
|
|
if (Address >= 0xA3F00000 && Address < 0xC0000000)
|
|
{
|
|
if (Address < 0xA4000000 || Address >= 0xA4002000)
|
|
{
|
|
Address &= 0x1FFFFFFF;
|
|
if (!r4300i_LW_NonMemory(Address,&GPR[Opcode.rt].UW[0]))
|
|
{
|
|
if (ShowUnhandledMemory)
|
|
{
|
|
DisplayError("Failed to load word\n\nIn LW",Address);
|
|
}
|
|
}
|
|
GPR[Opcode.rt].DW = GPR[Opcode.rt].W[0];
|
|
return;
|
|
}
|
|
}
|
|
if (!r4300i_LW_VAddr(Address,&GPR[Opcode.rt].UW[0])) {
|
|
if (ShowTLBMisses) {
|
|
DisplayError("LW TLB: %X",Address);
|
|
}
|
|
TLB_READ_EXCEPTION(Address);
|
|
} else {
|
|
GPR[Opcode.rt].DW = GPR[Opcode.rt].W[0];
|
|
//TranslateVaddr(&Address);
|
|
//if (Address == 0x00090AA0) {
|
|
// LogMessage("%X: Read %X from %X",PROGRAM_COUNTER,GPR[Opcode.rt].UW[0],GPR[Opcode.base].UW[0] + (short)Opcode.offset);
|
|
//}
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_LBU (void) {
|
|
DWORD Address = GPR[Opcode.base].UW[0] + (short)Opcode.offset;
|
|
if (!r4300i_LB_VAddr(Address,&GPR[Opcode.rt].UB[0])) {
|
|
if (ShowTLBMisses) {
|
|
DisplayError("LBU TLB: %X",Address);
|
|
}
|
|
TLB_READ_EXCEPTION(Address);
|
|
} else {
|
|
GPR[Opcode.rt].UDW = GPR[Opcode.rt].UB[0];
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_LHU (void) {
|
|
DWORD Address = GPR[Opcode.base].UW[0] + (short)Opcode.offset;
|
|
if ((Address & 1) != 0) { ADDRESS_ERROR_EXCEPTION(Address,TRUE); }
|
|
if (!r4300i_LH_VAddr(Address,&GPR[Opcode.rt].UHW[0])) {
|
|
if (ShowTLBMisses) {
|
|
DisplayError("LHU TLB: %X",Address);
|
|
}
|
|
TLB_READ_EXCEPTION(Address);
|
|
} else {
|
|
GPR[Opcode.rt].UDW = GPR[Opcode.rt].UHW[0];
|
|
}
|
|
}
|
|
|
|
DWORD LWR_MASK[4] = { 0xFFFFFF00, 0xFFFF0000, 0xFF000000, 0 };
|
|
int LWR_SHIFT[4] = { 24, 16 ,8, 0 };
|
|
|
|
void _fastcall r4300i_LWR (void) {
|
|
DWORD Offset, Address, Value;
|
|
|
|
Address = GPR[Opcode.base].UW[0] + (short)Opcode.offset;
|
|
Offset = Address & 3;
|
|
|
|
if (!r4300i_LW_VAddr((Address & ~3),&Value)) {
|
|
#ifndef EXTERNAL_RELEASE
|
|
DisplayError("LDL TLB: %X",Address);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
GPR[Opcode.rt].DW = (int)(GPR[Opcode.rt].W[0] & LWR_MASK[Offset]);
|
|
GPR[Opcode.rt].DW += (int)(Value >> LWR_SHIFT[Offset]);
|
|
}
|
|
|
|
void _fastcall r4300i_LWU (void) {
|
|
DWORD Address = GPR[Opcode.base].UW[0] + (short)Opcode.offset;
|
|
if ((Address & 3) != 0) { ADDRESS_ERROR_EXCEPTION(Address,TRUE); }
|
|
if (Opcode.rt == 0) { return; }
|
|
|
|
if (!r4300i_LW_VAddr(Address,&GPR[Opcode.rt].UW[0])) {
|
|
if (ShowTLBMisses) {
|
|
DisplayError("LWU TLB: %X",Address);
|
|
}
|
|
TLB_READ_EXCEPTION(Address);
|
|
} else {
|
|
GPR[Opcode.rt].UDW = GPR[Opcode.rt].UW[0];
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_SB (void) {
|
|
DWORD Address = GPR[Opcode.base].UW[0] + (short)Opcode.offset;
|
|
if (!r4300i_SB_VAddr(Address,GPR[Opcode.rt].UB[0])) {
|
|
#ifndef EXTERNAL_RELEASE
|
|
DisplayError("SB TLB: %X",Address);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_SH (void) {
|
|
DWORD Address = GPR[Opcode.base].UW[0] + (short)Opcode.offset;
|
|
if ((Address & 1) != 0) { ADDRESS_ERROR_EXCEPTION(Address,FALSE); }
|
|
if (!r4300i_SH_VAddr(Address,GPR[Opcode.rt].UHW[0])) {
|
|
#ifndef EXTERNAL_RELEASE
|
|
DisplayError("SH TLB: %X",Address);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
DWORD SWL_MASK[4] = { 0,0xFF000000,0xFFFF0000,0xFFFFFF00 };
|
|
int SWL_SHIFT[4] = { 0, 8, 16, 24 };
|
|
|
|
void _fastcall r4300i_SWL (void) {
|
|
DWORD Offset, Address, Value;
|
|
|
|
Address = GPR[Opcode.base].UW[0] + (short)Opcode.offset;
|
|
Offset = Address & 3;
|
|
|
|
if (!r4300i_LW_VAddr((Address & ~3),&Value)) {
|
|
#ifndef EXTERNAL_RELEASE
|
|
DisplayError("SWL TLB: %X",Address);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
Value &= SWL_MASK[Offset];
|
|
Value += GPR[Opcode.rt].UW[0] >> SWL_SHIFT[Offset];
|
|
|
|
if (!r4300i_SW_VAddr((Address & ~0x03),Value)) {
|
|
#ifndef EXTERNAL_RELEASE
|
|
DisplayError("SWL TLB: %X",Address);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
void _fastcall r4300i_SW (void) {
|
|
DWORD Address = GPR[Opcode.base].UW[0] + (short)Opcode.offset;
|
|
if ((Address & 3) != 0) { ADDRESS_ERROR_EXCEPTION(Address,FALSE); }
|
|
#if (!defined(EXTERNAL_RELEASE))
|
|
Log_SW(PROGRAM_COUNTER,Address,GPR[Opcode.rt].UW[0]);
|
|
#endif
|
|
if (Address >= 0xA3F00000 && Address < 0xC0000000)
|
|
{
|
|
if (Address < 0xA4000000 || Address >= 0xA4002000)
|
|
{
|
|
Address &= 0x1FFFFFFF;
|
|
if (!r4300i_SW_NonMemory(Address,GPR[Opcode.rt].UW[0]))
|
|
{
|
|
if (ShowUnhandledMemory)
|
|
{
|
|
DisplayError("Failed to load word\n\nIn SW",Address);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
if (!r4300i_SW_VAddr(Address,GPR[Opcode.rt].UW[0])) {
|
|
#ifndef EXTERNAL_RELEASE
|
|
DisplayError("SW TLB: %X",Address);
|
|
#endif
|
|
}
|
|
//TranslateVaddr(&Address);
|
|
//if (Address == 0x00090AA0) {
|
|
// LogMessage("%X: Write %X to %X",PROGRAM_COUNTER,GPR[Opcode.rt].UW[0],GPR[Opcode.base].UW[0] + (short)Opcode.offset);
|
|
//}
|
|
}
|
|
|
|
QWORD SDL_MASK[8] = { 0,0xFF00000000000000,
|
|
0xFFFF000000000000,
|
|
0xFFFFFF0000000000,
|
|
0xFFFFFFFF00000000,
|
|
0xFFFFFFFFFF000000,
|
|
0xFFFFFFFFFFFF0000,
|
|
0xFFFFFFFFFFFFFF00
|
|
};
|
|
int SDL_SHIFT[8] = { 0, 8, 16, 24, 32, 40, 48, 56 };
|
|
|
|
void _fastcall r4300i_SDL (void) {
|
|
DWORD Offset, Address;
|
|
QWORD Value;
|
|
|
|
Address = GPR[Opcode.base].UW[0] + (short)Opcode.offset;
|
|
Offset = Address & 7;
|
|
|
|
if (!r4300i_LD_VAddr((Address & ~7),&Value)) {
|
|
#ifndef EXTERNAL_RELEASE
|
|
DisplayError("SDL TLB: %X",Address);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
Value &= SDL_MASK[Offset];
|
|
Value += GPR[Opcode.rt].UDW >> SDL_SHIFT[Offset];
|
|
|
|
if (!r4300i_SD_VAddr((Address & ~7),Value)) {
|
|
#ifndef EXTERNAL_RELEASE
|
|
DisplayError("SDL TLB: %X",Address);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
QWORD SDR_MASK[8] = { 0x00FFFFFFFFFFFFFF,
|
|
0x0000FFFFFFFFFFFF,
|
|
0x000000FFFFFFFFFF,
|
|
0x00000000FFFFFFFF,
|
|
0x0000000000FFFFFF,
|
|
0x000000000000FFFF,
|
|
0x00000000000000FF,
|
|
0x0000000000000000
|
|
};
|
|
int SDR_SHIFT[8] = { 56,48,40,32,24,16,8,0 };
|
|
|
|
void _fastcall r4300i_SDR (void) {
|
|
DWORD Offset, Address;
|
|
QWORD Value;
|
|
|
|
Address = GPR[Opcode.base].UW[0] + (short)Opcode.offset;
|
|
Offset = Address & 7;
|
|
|
|
if (!r4300i_LD_VAddr((Address & ~7),&Value)) {
|
|
#ifndef EXTERNAL_RELEASE
|
|
DisplayError("SDL TLB: %X",Address);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
Value &= SDR_MASK[Offset];
|
|
Value += GPR[Opcode.rt].UDW << SDR_SHIFT[Offset];
|
|
|
|
if (!r4300i_SD_VAddr((Address & ~7),Value)) {
|
|
#ifndef EXTERNAL_RELEASE
|
|
DisplayError("SDL TLB: %X",Address);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
DWORD SWR_MASK[4] = { 0x00FFFFFF,0x0000FFFF,0x000000FF,0x00000000 };
|
|
int SWR_SHIFT[4] = { 24, 16 , 8, 0 };
|
|
|
|
void _fastcall r4300i_SWR (void) {
|
|
DWORD Offset, Address, Value;
|
|
|
|
Address = GPR[Opcode.base].UW[0] + (short)Opcode.offset;
|
|
Offset = Address & 3;
|
|
|
|
if (!r4300i_LW_VAddr((Address & ~3),&Value)) {
|
|
#ifndef EXTERNAL_RELEASE
|
|
DisplayError("SWL TLB: %X",Address);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
Value &= SWR_MASK[Offset];
|
|
Value += GPR[Opcode.rt].UW[0] << SWR_SHIFT[Offset];
|
|
|
|
if (!r4300i_SW_VAddr((Address & ~0x03),Value)) {
|
|
#ifndef EXTERNAL_RELEASE
|
|
DisplayError("SWL TLB: %X",Address);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_CACHE (void) {
|
|
#if (!defined(EXTERNAL_RELEASE))
|
|
if (!LogOptions.LogCache) { return; }
|
|
LogMessage("%08X: Cache operation %d, 0x%08X", PROGRAM_COUNTER, Opcode.rt,
|
|
GPR[Opcode.base].UW[0] + (short)Opcode.offset );
|
|
#endif
|
|
}
|
|
|
|
void _fastcall r4300i_LL (void) {
|
|
#ifdef OLD_CODE
|
|
DWORD Address = GPR[Opcode.base].UW[0] + (short)Opcode.offset;
|
|
if ((Address & 3) != 0) { ADDRESS_ERROR_EXCEPTION(Address,TRUE); }
|
|
|
|
if (Opcode.rt == 0) { return; }
|
|
|
|
if (!r4300i_LW_VAddr(Address,&GPR[Opcode.rt].UW[0])) {
|
|
if (ShowTLBMisses) {
|
|
DisplayError("LW TLB: %X",Address);
|
|
}
|
|
TLB_READ_EXCEPTION(Address);
|
|
} else {
|
|
GPR[Opcode.rt].DW = GPR[Opcode.rt].W[0];
|
|
}
|
|
LLBit = 1;
|
|
LLAddr = Address;
|
|
TranslateVaddr(&LLAddr);
|
|
#else
|
|
BreakPoint(__FILE__,__LINE__);
|
|
#endif
|
|
}
|
|
|
|
void _fastcall r4300i_LWC1 (void) {
|
|
DWORD Address = GPR[Opcode.base].UW[0] + (DWORD)((short)Opcode.offset);
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
if ((Address & 3) != 0) { ADDRESS_ERROR_EXCEPTION(Address,TRUE); }
|
|
if (!r4300i_LW_VAddr(Address,&*(DWORD *)FPRFloatLocation[Opcode.ft])) {
|
|
if (ShowTLBMisses) {
|
|
DisplayError("LWC1 TLB: %X",Address);
|
|
}
|
|
TLB_READ_EXCEPTION(Address);
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_SC (void) {
|
|
DWORD Address = GPR[Opcode.base].UW[0] + (short)Opcode.offset;
|
|
if ((Address & 3) != 0) { ADDRESS_ERROR_EXCEPTION(Address,FALSE); }
|
|
#if (!defined(EXTERNAL_RELEASE))
|
|
Log_SW(PROGRAM_COUNTER,Address,GPR[Opcode.rt].UW[0]);
|
|
#endif
|
|
if (LLBit == 1) {
|
|
if (!r4300i_SW_VAddr(Address,GPR[Opcode.rt].UW[0])) {
|
|
DisplayError("SW TLB: %X",Address);
|
|
}
|
|
}
|
|
GPR[Opcode.rt].UW[0] = LLBit;
|
|
}
|
|
|
|
void _fastcall r4300i_LD (void) {
|
|
DWORD Address = GPR[Opcode.base].UW[0] + (short)Opcode.offset;
|
|
if ((Address & 7) != 0) { ADDRESS_ERROR_EXCEPTION(Address,TRUE); }
|
|
if (!r4300i_LD_VAddr(Address,&GPR[Opcode.rt].UDW)) {
|
|
#ifndef EXTERNAL_RELEASE
|
|
DisplayError("LD TLB: %X",Address);
|
|
#endif
|
|
}
|
|
#ifdef Interpreter_StackTest
|
|
if (Opcode.rt == 29) {
|
|
StackValue = GPR[Opcode.rt].W[0];
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
void _fastcall r4300i_LDC1 (void) {
|
|
DWORD Address = GPR[Opcode.base].UW[0] + (short)Opcode.offset;
|
|
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
if ((Address & 7) != 0) { ADDRESS_ERROR_EXCEPTION(Address,TRUE); }
|
|
if (!r4300i_LD_VAddr(Address,&*(unsigned __int64 *)FPRDoubleLocation[Opcode.ft])) {
|
|
#ifndef EXTERNAL_RELEASE
|
|
DisplayError("LD TLB: %X",Address);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_SWC1 (void) {
|
|
DWORD Address = GPR[Opcode.base].UW[0] + (short)Opcode.offset;
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
if ((Address & 3) != 0) { ADDRESS_ERROR_EXCEPTION(Address,FALSE); }
|
|
|
|
if (!r4300i_SW_VAddr(Address,*(DWORD *)FPRFloatLocation[Opcode.ft])) {
|
|
#ifndef EXTERNAL_RELEASE
|
|
DisplayError("SWC1 TLB: %X",Address);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_SDC1 (void) {
|
|
DWORD Address = GPR[Opcode.base].UW[0] + (short)Opcode.offset;
|
|
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
if ((Address & 7) != 0) { ADDRESS_ERROR_EXCEPTION(Address,FALSE); }
|
|
if (!r4300i_SD_VAddr(Address,*(__int64 *)FPRDoubleLocation[Opcode.ft])) {
|
|
#ifndef EXTERNAL_RELEASE
|
|
DisplayError("SDC1 TLB: %X",Address);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_SD (void) {
|
|
DWORD Address = GPR[Opcode.base].UW[0] + (short)Opcode.offset;
|
|
if ((Address & 7) != 0) { ADDRESS_ERROR_EXCEPTION(Address,FALSE); }
|
|
if (!r4300i_SD_VAddr(Address,GPR[Opcode.rt].UDW)) {
|
|
#ifndef EXTERNAL_RELEASE
|
|
DisplayError("SD TLB: %X",Address);
|
|
#endif
|
|
}
|
|
}
|
|
/********************** R4300i OpCodes: Special **********************/
|
|
void _fastcall r4300i_SPECIAL_SLL (void) {
|
|
GPR[Opcode.rd].DW = (GPR[Opcode.rt].W[0] << Opcode.sa);
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_SRL (void) {
|
|
GPR[Opcode.rd].DW = (int)(GPR[Opcode.rt].UW[0] >> Opcode.sa);
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_SRA (void) {
|
|
GPR[Opcode.rd].DW = (GPR[Opcode.rt].W[0] >> Opcode.sa);
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_SLLV (void) {
|
|
if (Opcode.rd == 0) { return; }
|
|
GPR[Opcode.rd].DW = (GPR[Opcode.rt].W[0] << (GPR[Opcode.rs].UW[0] & 0x1F));
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_SRLV (void) {
|
|
GPR[Opcode.rd].DW = (int)(GPR[Opcode.rt].UW[0] >> (GPR[Opcode.rs].UW[0] & 0x1F));
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_SRAV (void) {
|
|
GPR[Opcode.rd].DW = (GPR[Opcode.rt].W[0] >> (GPR[Opcode.rs].UW[0] & 0x1F));
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_JR (void) {
|
|
NextInstruction = DELAY_SLOT;
|
|
JumpToLocation = GPR[Opcode.rs].UW[0];
|
|
TestTimer = TRUE;
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_JALR (void) {
|
|
NextInstruction = DELAY_SLOT;
|
|
JumpToLocation = GPR[Opcode.rs].UW[0];
|
|
GPR[Opcode.rd].DW = (long)(PROGRAM_COUNTER + 8);
|
|
TestTimer = TRUE;
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_SYSCALL (void) {
|
|
DoSysCallException(NextInstruction == JUMP);
|
|
NextInstruction = JUMP;
|
|
JumpToLocation = PROGRAM_COUNTER;
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_BREAK (void) {
|
|
DoBreakException(NextInstruction == JUMP);
|
|
NextInstruction = JUMP;
|
|
JumpToLocation = PROGRAM_COUNTER;
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_SYNC (void) {
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_MFHI (void) {
|
|
GPR[Opcode.rd].DW = HI.DW;
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_MTHI (void) {
|
|
HI.DW = GPR[Opcode.rs].DW;
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_MFLO (void) {
|
|
GPR[Opcode.rd].DW = LO.DW;
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_MTLO (void) {
|
|
LO.DW = GPR[Opcode.rs].DW;
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_DSLLV (void) {
|
|
GPR[Opcode.rd].DW = GPR[Opcode.rt].DW << (GPR[Opcode.rs].UW[0] & 0x3F);
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_DSRLV (void) {
|
|
GPR[Opcode.rd].UDW = GPR[Opcode.rt].UDW >> (GPR[Opcode.rs].UW[0] & 0x3F);
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_DSRAV (void) {
|
|
GPR[Opcode.rd].DW = GPR[Opcode.rt].DW >> (GPR[Opcode.rs].UW[0] & 0x3F);
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_MULT (void) {
|
|
HI.DW = (_int64)(GPR[Opcode.rs].W[0]) * (_int64)(GPR[Opcode.rt].W[0]);
|
|
LO.DW = HI.W[0];
|
|
HI.DW = HI.W[1];
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_MULTU (void) {
|
|
HI.DW = (unsigned _int64)(GPR[Opcode.rs].UW[0]) * (unsigned _int64)(GPR[Opcode.rt].UW[0]);
|
|
LO.DW = HI.W[0];
|
|
HI.DW = HI.W[1];
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_DIV (void) {
|
|
if ( GPR[Opcode.rt].UDW != 0 ) {
|
|
LO.DW = GPR[Opcode.rs].W[0] / GPR[Opcode.rt].W[0];
|
|
HI.DW = GPR[Opcode.rs].W[0] % GPR[Opcode.rt].W[0];
|
|
} else {
|
|
#ifndef EXTERNAL_RELEASE
|
|
DisplayError("DIV by 0 ???");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_DIVU (void) {
|
|
if ( GPR[Opcode.rt].UDW != 0 ) {
|
|
LO.DW = (int)(GPR[Opcode.rs].UW[0] / GPR[Opcode.rt].UW[0]);
|
|
HI.DW = (int)(GPR[Opcode.rs].UW[0] % GPR[Opcode.rt].UW[0]);
|
|
} else {
|
|
#ifndef EXTERNAL_RELEASE
|
|
DisplayError("DIVU by 0 ???");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_DMULT (void) {
|
|
MIPS_DWORD Tmp[3];
|
|
|
|
LO.UDW = (QWORD)GPR[Opcode.rs].UW[0] * (QWORD)GPR[Opcode.rt].UW[0];
|
|
Tmp[0].UDW = (_int64)GPR[Opcode.rs].W[1] * (_int64)(QWORD)GPR[Opcode.rt].UW[0];
|
|
Tmp[1].UDW = (_int64)(QWORD)GPR[Opcode.rs].UW[0] * (_int64)GPR[Opcode.rt].W[1];
|
|
HI.UDW = (_int64)GPR[Opcode.rs].W[1] * (_int64)GPR[Opcode.rt].W[1];
|
|
|
|
Tmp[2].UDW = (QWORD)LO.UW[1] + (QWORD)Tmp[0].UW[0] + (QWORD)Tmp[1].UW[0];
|
|
LO.UDW += ((QWORD)Tmp[0].UW[0] + (QWORD)Tmp[1].UW[0]) << 32;
|
|
HI.UDW += (QWORD)Tmp[0].W[1] + (QWORD)Tmp[1].W[1] + Tmp[2].UW[1];
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_DMULTU (void) {
|
|
MIPS_DWORD Tmp[3];
|
|
|
|
LO.UDW = (QWORD)GPR[Opcode.rs].UW[0] * (QWORD)GPR[Opcode.rt].UW[0];
|
|
Tmp[0].UDW = (QWORD)GPR[Opcode.rs].UW[1] * (QWORD)GPR[Opcode.rt].UW[0];
|
|
Tmp[1].UDW = (QWORD)GPR[Opcode.rs].UW[0] * (QWORD)GPR[Opcode.rt].UW[1];
|
|
HI.UDW = (QWORD)GPR[Opcode.rs].UW[1] * (QWORD)GPR[Opcode.rt].UW[1];
|
|
|
|
Tmp[2].UDW = (QWORD)LO.UW[1] + (QWORD)Tmp[0].UW[0] + (QWORD)Tmp[1].UW[0];
|
|
LO.UDW += ((QWORD)Tmp[0].UW[0] + (QWORD)Tmp[1].UW[0]) << 32;
|
|
HI.UDW += (QWORD)Tmp[0].UW[1] + (QWORD)Tmp[1].UW[1] + Tmp[2].UW[1];
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_DDIV (void) {
|
|
if ( GPR[Opcode.rt].UDW != 0 ) {
|
|
LO.DW = GPR[Opcode.rs].DW / GPR[Opcode.rt].DW;
|
|
HI.DW = GPR[Opcode.rs].DW % GPR[Opcode.rt].DW;
|
|
} else {
|
|
#ifndef EXTERNAL_RELEASE
|
|
DisplayError("DDIV by 0 ???");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_DDIVU (void) {
|
|
if ( GPR[Opcode.rt].UDW != 0 ) {
|
|
LO.UDW = GPR[Opcode.rs].UDW / GPR[Opcode.rt].UDW;
|
|
HI.UDW = GPR[Opcode.rs].UDW % GPR[Opcode.rt].UDW;
|
|
} else {
|
|
#ifndef EXTERNAL_RELEASE
|
|
DisplayError("DDIVU by 0 ???");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_ADD (void) {
|
|
GPR[Opcode.rd].DW = GPR[Opcode.rs].W[0] + GPR[Opcode.rt].W[0];
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_ADDU (void) {
|
|
GPR[Opcode.rd].DW = GPR[Opcode.rs].W[0] + GPR[Opcode.rt].W[0];
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_SUB (void) {
|
|
GPR[Opcode.rd].DW = GPR[Opcode.rs].W[0] - GPR[Opcode.rt].W[0];
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_SUBU (void) {
|
|
GPR[Opcode.rd].DW = GPR[Opcode.rs].W[0] - GPR[Opcode.rt].W[0];
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_AND (void) {
|
|
GPR[Opcode.rd].DW = GPR[Opcode.rs].DW & GPR[Opcode.rt].DW;
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_OR (void) {
|
|
GPR[Opcode.rd].DW = GPR[Opcode.rs].DW | GPR[Opcode.rt].DW;
|
|
#ifdef Interpreter_StackTest
|
|
if (Opcode.rd == 29) {
|
|
StackValue = GPR[Opcode.rd].W[0];
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_XOR (void) {
|
|
GPR[Opcode.rd].DW = GPR[Opcode.rs].DW ^ GPR[Opcode.rt].DW;
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_NOR (void) {
|
|
GPR[Opcode.rd].DW = ~(GPR[Opcode.rs].DW | GPR[Opcode.rt].DW);
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_SLT (void) {
|
|
if (GPR[Opcode.rs].DW < GPR[Opcode.rt].DW) {
|
|
GPR[Opcode.rd].DW = 1;
|
|
} else {
|
|
GPR[Opcode.rd].DW = 0;
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_SLTU (void) {
|
|
if (GPR[Opcode.rs].UDW < GPR[Opcode.rt].UDW) {
|
|
GPR[Opcode.rd].DW = 1;
|
|
} else {
|
|
GPR[Opcode.rd].DW = 0;
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_DADD (void) {
|
|
GPR[Opcode.rd].DW = GPR[Opcode.rs].DW + GPR[Opcode.rt].DW;
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_DADDU (void) {
|
|
GPR[Opcode.rd].DW = GPR[Opcode.rs].DW + GPR[Opcode.rt].DW;
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_DSUB (void) {
|
|
GPR[Opcode.rd].DW = GPR[Opcode.rs].DW - GPR[Opcode.rt].DW;
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_DSUBU (void) {
|
|
GPR[Opcode.rd].DW = GPR[Opcode.rs].DW - GPR[Opcode.rt].DW;
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_TEQ (void) {
|
|
if (GPR[Opcode.rs].DW == GPR[Opcode.rt].DW) {
|
|
#ifndef EXTERNAL_RELEASE
|
|
DisplayError("Should trap this ???");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_DSLL (void) {
|
|
GPR[Opcode.rd].DW = (GPR[Opcode.rt].DW << Opcode.sa);
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_DSRL (void) {
|
|
GPR[Opcode.rd].UDW = (GPR[Opcode.rt].UDW >> Opcode.sa);
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_DSRA (void) {
|
|
GPR[Opcode.rd].DW = (GPR[Opcode.rt].DW >> Opcode.sa);
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_DSLL32 (void) {
|
|
GPR[Opcode.rd].DW = (GPR[Opcode.rt].DW << (Opcode.sa + 32));
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_DSRL32 (void) {
|
|
GPR[Opcode.rd].UDW = (GPR[Opcode.rt].UDW >> (Opcode.sa + 32));
|
|
}
|
|
|
|
void _fastcall r4300i_SPECIAL_DSRA32 (void) {
|
|
GPR[Opcode.rd].DW = (GPR[Opcode.rt].DW >> (Opcode.sa + 32));
|
|
}
|
|
|
|
/********************** R4300i OpCodes: RegImm **********************/
|
|
void _fastcall r4300i_REGIMM_BLTZ (void) {
|
|
NextInstruction = DELAY_SLOT;
|
|
if (GPR[Opcode.rs].DW < 0) {
|
|
JumpToLocation = PROGRAM_COUNTER + ((short)Opcode.offset << 2) + 4;
|
|
TestInterpreterJump(PROGRAM_COUNTER,JumpToLocation,Opcode.rs,0);
|
|
} else {
|
|
JumpToLocation = PROGRAM_COUNTER + 8;
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_REGIMM_BGEZ (void) {
|
|
NextInstruction = DELAY_SLOT;
|
|
if (GPR[Opcode.rs].DW >= 0) {
|
|
JumpToLocation = PROGRAM_COUNTER + ((short)Opcode.offset << 2) + 4;
|
|
TestInterpreterJump(PROGRAM_COUNTER,JumpToLocation,Opcode.rs,0);
|
|
} else {
|
|
JumpToLocation = PROGRAM_COUNTER + 8;
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_REGIMM_BLTZL (void) {
|
|
if (GPR[Opcode.rs].DW < 0) {
|
|
NextInstruction = DELAY_SLOT;
|
|
JumpToLocation = PROGRAM_COUNTER + ((short)Opcode.offset << 2) + 4;
|
|
TestInterpreterJump(PROGRAM_COUNTER,JumpToLocation,Opcode.rs,0);
|
|
} else {
|
|
NextInstruction = JUMP;
|
|
JumpToLocation = PROGRAM_COUNTER + 8;
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_REGIMM_BGEZL (void) {
|
|
if (GPR[Opcode.rs].DW >= 0) {
|
|
NextInstruction = DELAY_SLOT;
|
|
JumpToLocation = PROGRAM_COUNTER + ((short)Opcode.offset << 2) + 4;
|
|
TestInterpreterJump(PROGRAM_COUNTER,JumpToLocation,Opcode.rs,0);
|
|
} else {
|
|
NextInstruction = JUMP;
|
|
JumpToLocation = PROGRAM_COUNTER + 8;
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_REGIMM_BLTZAL (void) {
|
|
NextInstruction = DELAY_SLOT;
|
|
if (GPR[Opcode.rs].DW < 0) {
|
|
JumpToLocation = PROGRAM_COUNTER + ((short)Opcode.offset << 2) + 4;
|
|
TestInterpreterJump(PROGRAM_COUNTER,JumpToLocation,Opcode.rs,0);
|
|
} else {
|
|
JumpToLocation = PROGRAM_COUNTER + 8;
|
|
}
|
|
GPR[31].DW= (long)(PROGRAM_COUNTER + 8);
|
|
}
|
|
|
|
void _fastcall r4300i_REGIMM_BGEZAL (void) {
|
|
NextInstruction = DELAY_SLOT;
|
|
if (GPR[Opcode.rs].DW >= 0) {
|
|
JumpToLocation = PROGRAM_COUNTER + ((short)Opcode.offset << 2) + 4;
|
|
TestInterpreterJump(PROGRAM_COUNTER,JumpToLocation,Opcode.rs,0);
|
|
} else {
|
|
JumpToLocation = PROGRAM_COUNTER + 8;
|
|
}
|
|
GPR[31].DW = (long)(PROGRAM_COUNTER + 8);
|
|
}
|
|
/************************** COP0 functions **************************/
|
|
void _fastcall r4300i_COP0_MF (void) {
|
|
#if (!defined(EXTERNAL_RELEASE))
|
|
if (LogOptions.LogCP0reads) {
|
|
LogMessage("%08X: R4300i Read from %s (0x%08X)", PROGRAM_COUNTER,
|
|
Cop0_Name[Opcode.rd], CP0[Opcode.rd]);
|
|
}
|
|
#endif
|
|
GPR[Opcode.rt].DW = (int)CP0[Opcode.rd];
|
|
}
|
|
|
|
void _fastcall r4300i_COP0_MT (void) {
|
|
#if (!defined(EXTERNAL_RELEASE))
|
|
if (LogOptions.LogCP0changes) {
|
|
LogMessage("%08X: Writing 0x%X to %s register (Originally: 0x%08X)",PROGRAM_COUNTER,
|
|
GPR[Opcode.rt].UW[0],Cop0_Name[Opcode.rd], CP0[Opcode.rd]);
|
|
if (Opcode.rd == 11) { //Compare
|
|
LogMessage("%08X: Cause register changed from %08X to %08X",PROGRAM_COUNTER,
|
|
CAUSE_REGISTER, (CAUSE_REGISTER & ~CAUSE_IP7));
|
|
}
|
|
}
|
|
#endif
|
|
switch (Opcode.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
|
|
CP0[Opcode.rd] = GPR[Opcode.rt].UW[0];
|
|
break;
|
|
case 4: //Context
|
|
CP0[Opcode.rd] = GPR[Opcode.rt].UW[0] & 0xFF800000;
|
|
break;
|
|
case 9: //Count
|
|
CP0[Opcode.rd]= GPR[Opcode.rt].UW[0];
|
|
ChangeCompareTimer();
|
|
break;
|
|
case 11: //Compare
|
|
CP0[Opcode.rd] = GPR[Opcode.rt].UW[0];
|
|
FAKE_CAUSE_REGISTER &= ~CAUSE_IP7;
|
|
ChangeCompareTimer();
|
|
break;
|
|
case 12: //Status
|
|
if ((CP0[Opcode.rd] ^ GPR[Opcode.rt].UW[0]) != 0) {
|
|
CP0[Opcode.rd] = GPR[Opcode.rt].UW[0];
|
|
SetFpuLocations();
|
|
} else {
|
|
CP0[Opcode.rd] = GPR[Opcode.rt].UW[0];
|
|
}
|
|
if ((CP0[Opcode.rd] & 0x18) != 0) {
|
|
#ifndef EXTERNAL_RELEASE
|
|
DisplayError("Left kernel mode ??");
|
|
#endif
|
|
}
|
|
CheckInterrupts();
|
|
break;
|
|
case 13: //cause
|
|
CP0[Opcode.rd] &= 0xFFFFCFF;
|
|
#ifndef EXTERNAL_RELEASE
|
|
if ((GPR[Opcode.rt].UW[0] & 0x300) != 0 ){ DisplayError("Set IP0 or IP1"); }
|
|
#endif
|
|
break;
|
|
default:
|
|
R4300i_UnknownOpcode();
|
|
}
|
|
}
|
|
|
|
/************************** COP0 CO functions ***********************/
|
|
void _fastcall r4300i_COP0_CO_TLBR (void) {
|
|
if (!UseTlb) { return; }
|
|
TLB_ReadEntry();
|
|
}
|
|
|
|
void _fastcall r4300i_COP0_CO_TLBWI (void) {
|
|
if (!UseTlb) { return; }
|
|
TLB_WriteEntry(INDEX_REGISTER & 0x1F,FALSE);
|
|
}
|
|
|
|
void _fastcall r4300i_COP0_CO_TLBWR (void) {
|
|
if (!UseTlb) { return; }
|
|
TLB_WriteEntry(RANDOM_REGISTER & 0x1F,TRUE);
|
|
}
|
|
|
|
void _fastcall r4300i_COP0_CO_TLBP (void) {
|
|
if (!UseTlb) { return; }
|
|
TLB_Probe();
|
|
}
|
|
|
|
void _fastcall r4300i_COP0_CO_ERET (void) {
|
|
NextInstruction = JUMP;
|
|
if ((STATUS_REGISTER & STATUS_ERL) != 0) {
|
|
JumpToLocation = ERROREPC_REGISTER;
|
|
STATUS_REGISTER &= ~STATUS_ERL;
|
|
} else {
|
|
JumpToLocation = EPC_REGISTER;
|
|
STATUS_REGISTER &= ~STATUS_EXL;
|
|
}
|
|
LLBit = 0;
|
|
CheckInterrupts();
|
|
TestTimer = TRUE;
|
|
}
|
|
|
|
/************************** COP1 functions **************************/
|
|
void _fastcall r4300i_COP1_MF (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
GPR[Opcode.rt].DW = *(int *)FPRFloatLocation[Opcode.fs];
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_DMF (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
GPR[Opcode.rt].DW = *(__int64 *)FPRDoubleLocation[Opcode.fs];
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_CF (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
if (Opcode.fs != 31 && Opcode.fs != 0) {
|
|
#ifndef EXTERNAL_RELEASE
|
|
DisplayError("CFC1 what register are you writing to ?");
|
|
#endif
|
|
return;
|
|
}
|
|
GPR[Opcode.rt].DW = (int)FPCR[Opcode.fs];
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_MT (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
*(int *)FPRFloatLocation[Opcode.fs] = GPR[Opcode.rt].W[0];
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_DMT (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
*(__int64 *)FPRDoubleLocation[Opcode.fs] = GPR[Opcode.rt].DW;
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_CT (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
if (Opcode.fs == 31) {
|
|
FPCR[Opcode.fs] = GPR[Opcode.rt].W[0];
|
|
switch((FPCR[Opcode.fs] & 3)) {
|
|
case 0: RoundingModel = _RC_NEAR; break;
|
|
case 1: RoundingModel = _RC_CHOP; break;
|
|
case 2: RoundingModel = _RC_UP; break;
|
|
case 3: RoundingModel = _RC_DOWN; break;
|
|
}
|
|
return;
|
|
}
|
|
#ifndef EXTERNAL_RELEASE
|
|
DisplayError("CTC1 what register are you writing to ?");
|
|
#endif
|
|
}
|
|
|
|
/************************* COP1: BC1 functions ***********************/
|
|
void _fastcall r4300i_COP1_BCF (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
NextInstruction = DELAY_SLOT;
|
|
if ((FPCR[31] & FPCSR_C) == 0) {
|
|
JumpToLocation = PROGRAM_COUNTER + ((short)Opcode.offset << 2) + 4;
|
|
} else {
|
|
JumpToLocation = PROGRAM_COUNTER + 8;
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_BCT (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
NextInstruction = DELAY_SLOT;
|
|
if ((FPCR[31] & FPCSR_C) != 0) {
|
|
JumpToLocation = PROGRAM_COUNTER + ((short)Opcode.offset << 2) + 4;
|
|
} else {
|
|
JumpToLocation = PROGRAM_COUNTER + 8;
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_BCFL (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
if ((FPCR[31] & FPCSR_C) == 0) {
|
|
NextInstruction = DELAY_SLOT;
|
|
JumpToLocation = PROGRAM_COUNTER + ((short)Opcode.offset << 2) + 4;
|
|
} else {
|
|
NextInstruction = JUMP;
|
|
JumpToLocation = PROGRAM_COUNTER + 8;
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_BCTL (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
if ((FPCR[31] & FPCSR_C) != 0) {
|
|
NextInstruction = DELAY_SLOT;
|
|
JumpToLocation = PROGRAM_COUNTER + ((short)Opcode.offset << 2) + 4;
|
|
} else {
|
|
NextInstruction = JUMP;
|
|
JumpToLocation = PROGRAM_COUNTER + 8;
|
|
}
|
|
}
|
|
/************************** COP1: S functions ************************/
|
|
__inline void Float_RoundToInteger32( int * Dest, float * Source ) {
|
|
_asm {
|
|
mov esi, [Source]
|
|
mov edi, [Dest]
|
|
fld dword ptr [esi]
|
|
fistp dword ptr [edi]
|
|
}
|
|
}
|
|
|
|
__inline void Float_RoundToInteger64( __int64 * Dest, float * Source ) {
|
|
_asm {
|
|
mov esi, [Source]
|
|
mov edi, [Dest]
|
|
fld dword ptr [esi]
|
|
fistp qword ptr [edi]
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_S_ADD (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(RoundingModel,_MCW_RC);
|
|
*(float *)FPRFloatLocation[Opcode.fd] = (*(float *)FPRFloatLocation[Opcode.fs] + *(float *)FPRFloatLocation[Opcode.ft]);
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_S_SUB (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(RoundingModel,_MCW_RC);
|
|
*(float *)FPRFloatLocation[Opcode.fd] = (*(float *)FPRFloatLocation[Opcode.fs] - *(float *)FPRFloatLocation[Opcode.ft]);
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_S_MUL (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(RoundingModel,_MCW_RC);
|
|
*(float *)FPRFloatLocation[Opcode.fd] = (*(float *)FPRFloatLocation[Opcode.fs] * *(float *)FPRFloatLocation[Opcode.ft]);
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_S_DIV (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(RoundingModel,_MCW_RC);
|
|
*(float *)FPRFloatLocation[Opcode.fd] = (*(float *)FPRFloatLocation[Opcode.fs] / *(float *)FPRFloatLocation[Opcode.ft]);
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_S_SQRT (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(RoundingModel,_MCW_RC);
|
|
*(float *)FPRFloatLocation[Opcode.fd] = (float)sqrt(*(float *)FPRFloatLocation[Opcode.fs]);
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_S_ABS (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(RoundingModel,_MCW_RC);
|
|
*(float *)FPRFloatLocation[Opcode.fd] = (float)fabs(*(float *)FPRFloatLocation[Opcode.fs]);
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_S_MOV (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(RoundingModel,_MCW_RC);
|
|
*(float *)FPRFloatLocation[Opcode.fd] = *(float *)FPRFloatLocation[Opcode.fs];
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_S_NEG (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(RoundingModel,_MCW_RC);
|
|
*(float *)FPRFloatLocation[Opcode.fd] = (*(float *)FPRFloatLocation[Opcode.fs] * -1.0f);
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_S_TRUNC_L (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(_RC_CHOP,_MCW_RC);
|
|
Float_RoundToInteger64(&*(__int64 *)FPRDoubleLocation[Opcode.fd],&*(float *)FPRFloatLocation[Opcode.fs]);
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_S_CEIL_L (void) { //added by Witten
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(_RC_UP,_MCW_RC);
|
|
Float_RoundToInteger64(&*(__int64 *)FPRDoubleLocation[Opcode.fd],&*(float *)FPRFloatLocation[Opcode.fs]);
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_S_FLOOR_L (void) { //added by Witten
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(_RC_DOWN,_MCW_RC);
|
|
Float_RoundToInteger64(&*(__int64 *)FPRDoubleLocation[Opcode.fd],&*(float *)FPRFloatLocation[Opcode.fs]);
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_S_ROUND_W (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(_RC_NEAR,_MCW_RC);
|
|
Float_RoundToInteger32(&*(int *)FPRFloatLocation[Opcode.fd],&*(float *)FPRFloatLocation[Opcode.fs]);
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_S_TRUNC_W (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(_RC_CHOP,_MCW_RC);
|
|
Float_RoundToInteger32(&*(int *)FPRFloatLocation[Opcode.fd],&*(float *)FPRFloatLocation[Opcode.fs]);
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_S_CEIL_W (void) { //added by Witten
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(_RC_UP,_MCW_RC);
|
|
Float_RoundToInteger32(&*(int *)FPRFloatLocation[Opcode.fd],&*(float *)FPRFloatLocation[Opcode.fs]);
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_S_FLOOR_W (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(_RC_DOWN,_MCW_RC);
|
|
Float_RoundToInteger32(&*(int *)FPRFloatLocation[Opcode.fd],&*(float *)FPRFloatLocation[Opcode.fs]);
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_S_CVT_D (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(RoundingModel,_MCW_RC);
|
|
*(double *)FPRDoubleLocation[Opcode.fd] = (double)(*(float *)FPRFloatLocation[Opcode.fs]);
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_S_CVT_W (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(RoundingModel,_MCW_RC);
|
|
Float_RoundToInteger32(&*(int *)FPRFloatLocation[Opcode.fd],&*(float *)FPRFloatLocation[Opcode.fs]);
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_S_CVT_L (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(RoundingModel,_MCW_RC);
|
|
Float_RoundToInteger64(&*(__int64 *)FPRDoubleLocation[Opcode.fd],&*(float *)FPRFloatLocation[Opcode.fs]);
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_S_CMP (void) {
|
|
int less, equal, unorded, condition;
|
|
float Temp0, Temp1;
|
|
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
|
|
Temp0 = *(float *)FPRFloatLocation[Opcode.fs];
|
|
Temp1 = *(float *)FPRFloatLocation[Opcode.ft];
|
|
|
|
if (_isnan(Temp0) || _isnan(Temp1)) {
|
|
#ifndef EXTERNAL_RELEASE
|
|
DisplayError("Nan ?");
|
|
#endif
|
|
less = FALSE;
|
|
equal = FALSE;
|
|
unorded = TRUE;
|
|
if ((Opcode.funct & 8) != 0) {
|
|
#ifndef EXTERNAL_RELEASE
|
|
DisplayError("Signal InvalidOperationException\nin r4300i_COP1_S_CMP\n%X %ff\n%X %ff",
|
|
Temp0,Temp0,Temp1,Temp1);
|
|
#endif
|
|
}
|
|
} else {
|
|
less = Temp0 < Temp1;
|
|
equal = Temp0 == Temp1;
|
|
unorded = FALSE;
|
|
}
|
|
|
|
condition = ((Opcode.funct & 4) && less) | ((Opcode.funct & 2) && equal) |
|
|
((Opcode.funct & 1) && unorded);
|
|
|
|
if (condition) {
|
|
FPCR[31] |= FPCSR_C;
|
|
} else {
|
|
FPCR[31] &= ~FPCSR_C;
|
|
}
|
|
|
|
}
|
|
|
|
/************************** COP1: D functions ************************/
|
|
__inline void Double_RoundToInteger32( int * Dest, double * Source ) {
|
|
_asm {
|
|
mov esi, [Source]
|
|
mov edi, [Dest]
|
|
fld qword ptr [esi]
|
|
fistp dword ptr [edi]
|
|
}
|
|
}
|
|
|
|
__inline void Double_RoundToInteger64( __int64 * Dest, double * Source ) {
|
|
_asm {
|
|
mov esi, [Source]
|
|
mov edi, [Dest]
|
|
fld qword ptr [esi]
|
|
fistp qword ptr [edi]
|
|
}
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_D_ADD (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(RoundingModel,_MCW_RC);
|
|
*(double *)FPRDoubleLocation[Opcode.fd] = *(double *)FPRDoubleLocation[Opcode.fs] + *(double *)FPRDoubleLocation[Opcode.ft];
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_D_SUB (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(RoundingModel,_MCW_RC);
|
|
*(double *)FPRDoubleLocation[Opcode.fd] = *(double *)FPRDoubleLocation[Opcode.fs] - *(double *)FPRDoubleLocation[Opcode.ft];
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_D_MUL (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(RoundingModel,_MCW_RC);
|
|
*(double *)FPRDoubleLocation[Opcode.fd] = *(double *)FPRDoubleLocation[Opcode.fs] * *(double *)FPRDoubleLocation[Opcode.ft];
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_D_DIV (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(RoundingModel,_MCW_RC);
|
|
*(double *)FPRDoubleLocation[Opcode.fd] = *(double *)FPRDoubleLocation[Opcode.fs] / *(double *)FPRDoubleLocation[Opcode.ft];
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_D_SQRT (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(RoundingModel,_MCW_RC);
|
|
*(double *)FPRDoubleLocation[Opcode.fd] = (double)sqrt(*(double *)FPRDoubleLocation[Opcode.fs]);
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_D_ABS (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(RoundingModel,_MCW_RC);
|
|
*(double *)FPRDoubleLocation[Opcode.fd] = fabs(*(double *)FPRDoubleLocation[Opcode.fs]);
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_D_MOV (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(RoundingModel,_MCW_RC);
|
|
*(__int64 *)FPRDoubleLocation[Opcode.fd] = *(__int64 *)FPRDoubleLocation[Opcode.fs];
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_D_NEG (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(RoundingModel,_MCW_RC);
|
|
*(double *)FPRDoubleLocation[Opcode.fd] = (*(double *)FPRDoubleLocation[Opcode.fs] * -1.0);
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_D_TRUNC_L (void) { //added by Witten
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(RC_CHOP,_MCW_RC);
|
|
Double_RoundToInteger64(&*(__int64 *)FPRFloatLocation[Opcode.fd],&*(double *)FPRDoubleLocation[Opcode.fs] );
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_D_CEIL_L (void) { //added by Witten
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(RC_UP,_MCW_RC);
|
|
Double_RoundToInteger64(&*(__int64 *)FPRFloatLocation[Opcode.fd],&*(double *)FPRDoubleLocation[Opcode.fs] );
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_D_FLOOR_L (void) { //added by Witten
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(_RC_DOWN,_MCW_RC);
|
|
Double_RoundToInteger64(&*(__int64 *)FPRDoubleLocation[Opcode.fd],&*(double *)FPRFloatLocation[Opcode.fs]);
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_D_ROUND_W (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(_RC_NEAR,_MCW_RC);
|
|
Double_RoundToInteger32(&*(DWORD *)FPRFloatLocation[Opcode.fd],&*(double *)FPRDoubleLocation[Opcode.fs] );
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_D_TRUNC_W (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(RC_CHOP,_MCW_RC);
|
|
Double_RoundToInteger32(&*(DWORD *)FPRFloatLocation[Opcode.fd],&*(double *)FPRDoubleLocation[Opcode.fs] );
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_D_CEIL_W (void) { //added by Witten
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(RC_UP,_MCW_RC);
|
|
Double_RoundToInteger32(&*(DWORD *)FPRFloatLocation[Opcode.fd],&*(double *)FPRDoubleLocation[Opcode.fs] );
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_D_FLOOR_W (void) { //added by Witten
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(_RC_DOWN,_MCW_RC);
|
|
Double_RoundToInteger32(&*(DWORD *)FPRDoubleLocation[Opcode.fd],&*(double *)FPRFloatLocation[Opcode.fs]);
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_D_CVT_S (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(RoundingModel,_MCW_RC);
|
|
*(float *)FPRFloatLocation[Opcode.fd] = (float)*(double *)FPRDoubleLocation[Opcode.fs];
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_D_CVT_W (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(RoundingModel,_MCW_RC);
|
|
Double_RoundToInteger32(&*(DWORD *)FPRFloatLocation[Opcode.fd],&*(double *)FPRDoubleLocation[Opcode.fs] );
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_D_CVT_L (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(RoundingModel,_MCW_RC);
|
|
Double_RoundToInteger64(&*(unsigned __int64 *)FPRDoubleLocation[Opcode.fd],&*(double *)FPRDoubleLocation[Opcode.fs]);
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_D_CMP (void) {
|
|
int less, equal, unorded, condition;
|
|
MIPS_DWORD Temp0, Temp1;
|
|
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
|
|
Temp0.DW = *(__int64 *)FPRDoubleLocation[Opcode.fs];
|
|
Temp1.DW = *(__int64 *)FPRDoubleLocation[Opcode.ft];
|
|
|
|
if (_isnan(Temp0.D) || _isnan(Temp1.D)) {
|
|
#ifndef EXTERNAL_RELEASE
|
|
DisplayError("Nan ?");
|
|
#endif
|
|
less = FALSE;
|
|
equal = FALSE;
|
|
unorded = TRUE;
|
|
if ((Opcode.funct & 8) != 0) {
|
|
#ifndef EXTERNAL_RELEASE
|
|
DisplayError("Signal InvalidOperationException\nin r4300i_COP1_D_CMP");
|
|
#endif
|
|
}
|
|
} else {
|
|
less = Temp0.D < Temp1.D;
|
|
equal = Temp0.D == Temp1.D;
|
|
unorded = FALSE;
|
|
}
|
|
|
|
condition = ((Opcode.funct & 4) && less) | ((Opcode.funct & 2) && equal) |
|
|
((Opcode.funct & 1) && unorded);
|
|
|
|
if (condition) {
|
|
FPCR[31] |= FPCSR_C;
|
|
} else {
|
|
FPCR[31] &= ~FPCSR_C;
|
|
}
|
|
}
|
|
|
|
/************************** COP1: W functions ************************/
|
|
void _fastcall r4300i_COP1_W_CVT_S (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(RoundingModel,_MCW_RC);
|
|
*(float *)FPRFloatLocation[Opcode.fd] = (float)*(int *)FPRFloatLocation[Opcode.fs];
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_W_CVT_D (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(RoundingModel,_MCW_RC);
|
|
*(double *)FPRDoubleLocation[Opcode.fd] = (double)*(int *)FPRFloatLocation[Opcode.fs];
|
|
}
|
|
|
|
/************************** COP1: L functions ************************/
|
|
void _fastcall r4300i_COP1_L_CVT_S (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(RoundingModel,_MCW_RC);
|
|
*(float *)FPRFloatLocation[Opcode.fd] = (float)*(__int64 *)FPRDoubleLocation[Opcode.fs];
|
|
}
|
|
|
|
void _fastcall r4300i_COP1_L_CVT_D (void) {
|
|
TEST_COP1_USABLE_EXCEPTION
|
|
_controlfp(RoundingModel,_MCW_RC);
|
|
*(double *)FPRDoubleLocation[Opcode.fd] = (double)*(__int64 *)FPRDoubleLocation[Opcode.fs];
|
|
}
|
|
|
|
/************************** Other functions **************************/
|
|
void _fastcall R4300i_UnknownOpcode (void) {
|
|
#ifdef OLD_CODE
|
|
char Message[200];
|
|
|
|
sprintf(Message,"%s: %08X\n%s\n\n", GS(MSG_UNHANDLED_OP), PROGRAM_COUNTER,
|
|
R4300iOpcodeName(Opcode.Hex,PROGRAM_COUNTER));
|
|
strcat(Message,"Stopping Emulation !");
|
|
|
|
#if (!defined(EXTERNAL_RELEASE))
|
|
if (HaveDebugger && !inFullScreen) {
|
|
int response;
|
|
|
|
strcat(Message,"\n\nDo you wish to enter the debugger ?");
|
|
|
|
response = MessageBox(NULL,Message,GS(MSG_MSGBOX_TITLE), MB_YESNO | MB_ICONERROR );
|
|
if (response == IDYES) {
|
|
Enter_R4300i_Commands_Window ();
|
|
}
|
|
ExitThread(0);
|
|
} else {
|
|
DisplayError(Message);
|
|
ExitThread(0);
|
|
}
|
|
#else
|
|
DisplayError(Message);
|
|
ExitThread(0);
|
|
#endif
|
|
#else
|
|
BreakPoint(__FILE__,__LINE__);
|
|
|
|
#endif
|
|
}
|