mirror of https://github.com/PCSX2/pcsx2.git
Committing the beginnings of a new PS2 Exception Handler! This is very much a work in progress, but it shouldn't really break (or fix) anything in its current state.
EE Interpreters: Fixed some signed/unsigned mistakes in some instructions, namely DIVU, DIVU1, unsigned Traps, and a couple unsigned right shifts. (all of these were already emulated correctly in the recs) Also: Removed the ThreadPriority stuff from Pcsx2, since it was a throwback to the days of Win95's unstable multitasker. If you really really feel like you need to change the thread priority of Pcsx2, use the Windows Task Manager or a third party util. git-svn-id: http://pcsx2.googlecode.com/svn/trunk@654 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
b0c3151aca
commit
f270064b41
|
@ -19,6 +19,7 @@
|
|||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "PsxCommon.h"
|
||||
#include "Common.h"
|
||||
|
||||
//THIS ALL IS FOR THE CDROM REGISTERS HANDLING
|
||||
|
||||
|
|
|
@ -50,22 +50,10 @@ extern TESTRUNARGS g_TestRun;
|
|||
#define PS2CLK 294912000 //hz /* 294.912 mhz */
|
||||
|
||||
|
||||
/* Config.PsxType == 1: PAL:
|
||||
VBlank interlaced 50.00 Hz
|
||||
VBlank non-interlaced 49.76 Hz
|
||||
HBlank 15.625 KHz
|
||||
Config.PsxType == 0: NSTC
|
||||
VBlank interlaced 59.94 Hz
|
||||
VBlank non-interlaced 59.82 Hz
|
||||
HBlank 15.73426573 KHz */
|
||||
|
||||
//Misc Clocks
|
||||
#define PSXPIXEL ((int)(PSXCLK / 13500000))
|
||||
#define PSXSOUNDCLK ((int)(48000))
|
||||
|
||||
#include "Plugins.h"
|
||||
#include "Misc.h"
|
||||
#include "SaveState.h"
|
||||
|
||||
#include "DebugTools/Debug.h"
|
||||
#include "R5900.h"
|
||||
#include "Memory.h"
|
||||
|
|
|
@ -61,6 +61,7 @@ protected:
|
|||
|
||||
namespace Exception
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// std::exception sucks, so I made a replacement.
|
||||
// Note, this class is "abstract" which means you shouldn't use it directly like, ever.
|
||||
// Use Exception::RuntimeError or Exception::LogicError instead.
|
||||
|
@ -78,7 +79,24 @@ namespace Exception
|
|||
const std::string& Message() const { return m_message; }
|
||||
const char* cMessage() const { return m_message.c_str(); }
|
||||
};
|
||||
|
||||
// This class is used as a base exception for things tossed by PS2 cpus (EE, IOP, etc).
|
||||
class Ps2Generic : public BaseException
|
||||
{
|
||||
public:
|
||||
virtual ~Ps2Generic() throw() {}
|
||||
|
||||
explicit Ps2Generic( const std::string& msg="The Ps2/MIPS state encountered a general exception." ) :
|
||||
Exception::BaseException( msg )
|
||||
{
|
||||
}
|
||||
|
||||
virtual u32 GetPc() const=0;
|
||||
virtual bool IsDelaySlot() const=0;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
class RuntimeError : public BaseException
|
||||
{
|
||||
public:
|
||||
|
@ -97,6 +115,8 @@ namespace Exception
|
|||
{}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
class OutOfMemory : public RuntimeError
|
||||
{
|
||||
public:
|
||||
|
@ -134,6 +154,8 @@ namespace Exception
|
|||
LogicError( msg ) {}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
class HardwareDeficiency : public RuntimeError
|
||||
{
|
||||
public:
|
||||
|
@ -184,8 +206,8 @@ namespace Exception
|
|||
RuntimeError( msg ) {}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// STREAMING EXCEPTIONS
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// STREAMING EXCEPTIONS
|
||||
|
||||
// Generic stream error. Contains the name of the stream and a message.
|
||||
// This exception is usually thrown via derrived classes, except in the (rare) case of a generic / unknown error.
|
||||
|
@ -264,8 +286,8 @@ namespace Exception
|
|||
Stream( objname, msg ) {}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// SAVESTATE EXCEPTIONS
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// SAVESTATE EXCEPTIONS
|
||||
|
||||
// Exception thrown when a corrupted or truncated savestate is encountered.
|
||||
class BadSavedState : public BadStream
|
||||
|
@ -321,6 +343,7 @@ namespace Exception
|
|||
|
||||
// A recoverable exception thrown when the CRC of the savestate does not match the
|
||||
// CRC returned by the Cdvd driver.
|
||||
// [feature not implemented yet]
|
||||
class StateCrcMismatch : public StateLoadError_Recoverable
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -381,14 +381,14 @@ void LWC1() {
|
|||
u32 addr;
|
||||
addr = cpuRegs.GPR.r[_Rs_].UL[0] + (s16)(cpuRegs.code & 0xffff); // force sign extension to 32bit
|
||||
if (addr & 0x00000003) { Console::Error( "FPU (LWC1 Opcode): Invalid Unaligned Memory Address" ); return; } // Should signal an exception?
|
||||
memRead32(addr, &fpuRegs.fpr[_Rt_].UL);
|
||||
fpuRegs.fpr[_Rt_].UL = memRead32(addr);
|
||||
}
|
||||
|
||||
void SWC1() {
|
||||
u32 addr;
|
||||
addr = cpuRegs.GPR.r[_Rs_].UL[0] + (s16)(cpuRegs.code & 0xffff); // force sign extension to 32bit
|
||||
if (addr & 0x00000003) { Console::Error( "FPU (SWC1 Opcode): Invalid Unaligned Memory Address" ); return; } // Should signal an exception?
|
||||
memWrite32(addr, fpuRegs.fpr[_Rt_].UL);
|
||||
memWrite32(addr, fpuRegs.fpr[_Rt_].UL);
|
||||
}
|
||||
|
||||
} } }
|
||||
|
|
|
@ -34,25 +34,19 @@ static std::string disOut;
|
|||
|
||||
// These macros are used to assemble the repassembler functions
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
static void debugI()
|
||||
{
|
||||
if (cpuRegs.GPR.n.r0.UD[0] || cpuRegs.GPR.n.r0.UD[1]) Console::Error("R0 is not zero!!!!");
|
||||
if( !IsDevBuild ) return;
|
||||
if( cpuRegs.GPR.n.r0.UD[0] || cpuRegs.GPR.n.r0.UD[1] ) Console::Error("R0 is not zero!!!!");
|
||||
}
|
||||
#else
|
||||
static void debugI() {}
|
||||
#endif
|
||||
|
||||
//long int runs=0;
|
||||
|
||||
static void execI()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
memRead32(cpuRegs.pc, &cpuRegs.code);
|
||||
debugI();
|
||||
#else
|
||||
cpuRegs.code = *(u32 *)PSM(cpuRegs.pc);
|
||||
#endif
|
||||
cpuRegs.code = memRead32( cpuRegs.pc );
|
||||
if( IsDebugBuild )
|
||||
debugI();
|
||||
|
||||
const OPCODE& opcode = GetCurrentInstruction();
|
||||
//use this to find out what opcodes your game uses. very slow! (rama)
|
||||
|
|
|
@ -25,6 +25,20 @@
|
|||
#include <math.h>
|
||||
#include "PsxCommon.h"
|
||||
|
||||
/* Config.PsxType == 1: PAL:
|
||||
VBlank interlaced 50.00 Hz
|
||||
VBlank non-interlaced 49.76 Hz
|
||||
HBlank 15.625 KHz
|
||||
Config.PsxType == 0: NSTC
|
||||
VBlank interlaced 59.94 Hz
|
||||
VBlank non-interlaced 59.82 Hz
|
||||
HBlank 15.73426573 KHz */
|
||||
|
||||
// Misc IOP Clocks
|
||||
#define PSXPIXEL ((int)(PSXCLK / 13500000))
|
||||
#define PSXSOUNDCLK ((int)(48000))
|
||||
|
||||
|
||||
psxCounter psxCounters[8];
|
||||
s32 psxNextCounter;
|
||||
u32 psxNextsCounter;
|
||||
|
|
|
@ -373,6 +373,9 @@ void psxMemReset()
|
|||
|
||||
// Trick! We're accessing RLUT here through WLUT, since it's the non-const pointer.
|
||||
// So the ones with a 1 prefixed (ala 0x18000, etc) are RLUT tables.
|
||||
|
||||
// Map IOP main memory, which is Read/Write, and mirrored three times
|
||||
// at 0x0, 0x8000, and 0xa000:
|
||||
for (int i=0; i<0x0080; i++)
|
||||
{
|
||||
psxMemWLUT[i + 0x0000] = (uptr)&psxM[(i & 0x1f) << 16];
|
||||
|
@ -385,7 +388,7 @@ void psxMemReset()
|
|||
psxMemWLUT[i + 0x1a000] = (uptr)&psxM[(i & 0x1f) << 16];
|
||||
}
|
||||
|
||||
// A few single-page allocations...
|
||||
// A few single-page allocations for things we store in special locations.
|
||||
psxMemWLUT[0x11f00] = (uptr)psxP;
|
||||
psxMemWLUT[0x11f80] = (uptr)psxH;
|
||||
psxMemWLUT[0x1bf80] = (uptr)psxH;
|
||||
|
|
|
@ -27,23 +27,26 @@ extern uptr *psxMemWLUT;
|
|||
extern const uptr *psxMemRLUT;
|
||||
|
||||
|
||||
// Obtains a write-safe pointer into the IOP's memory, with TLB address translation.
|
||||
// Hacky! This should really never be used, since anything reading or writing through the
|
||||
// TLB should be using iopMemRead/Write instead.
|
||||
template<typename T>
|
||||
// Obtains a writable pointer into the IOP's memory, with TLB address translation.
|
||||
// If the address maps to read-only memory, NULL is returned.
|
||||
// Hacky! This should really never be used, ever, since it bypasses the iop's Hardware
|
||||
// Register handler and SPU/DEV/USB maps.
|
||||
/*template<typename T>
|
||||
static __forceinline T* iopVirtMemW( u32 mem )
|
||||
{
|
||||
return (psxMemWLUT[(mem) >> 16] == 0) ? NULL : (T*)(psxMemRLUT[(mem) >> 16] + ((mem) & 0xffff));
|
||||
}
|
||||
return (psxMemWLUT[(mem) >> 16] == 0) ? NULL : (T*)(psxMemWLUT[(mem) >> 16] + ((mem) & 0xffff));
|
||||
}*/
|
||||
|
||||
// Obtains a read-safe pointer into the IOP's memory, with TLB address translation.
|
||||
// Hacky! This should really never be used, since anything reading or writing through the
|
||||
// TLB should be using iopMemRead/Write instead.
|
||||
// Obtains a read-safe pointer into the IOP's physical memory, with TLB address translation.
|
||||
// Returns NULL if the address maps to an invalid/unmapped physical address.
|
||||
//
|
||||
// Hacky! This should really never be used, since anything reading through the
|
||||
// TLB should be using iopMemRead/Write instead for each individual access. That ensures
|
||||
// correct handling of page boundary crossings.
|
||||
template<typename T>
|
||||
static __forceinline const T* iopVirtMemR( u32 mem )
|
||||
{
|
||||
return (psxMemRLUT[(mem) >> 16] == 0) ? NULL : (const T*)(psxMemRLUT[(mem) >> 16] + ((mem) & 0xffff));
|
||||
//return ((const T*)(psxMemRLUT[(mem) >> 16] + ((mem) & 0xffff)));
|
||||
}
|
||||
|
||||
// Obtains a pointer to the IOP's physical mapping (bypasses the TLB)
|
||||
|
@ -73,13 +76,6 @@ static __forceinline u8* iopPhysMem( u32 addr )
|
|||
#define psxHu16(mem) (*(u16*)&psxH[(mem) & 0xffff])
|
||||
#define psxHu32(mem) (*(u32*)&psxH[(mem) & 0xffff])
|
||||
|
||||
//#define PSXMs8(mem) (*(s8 *)_PSXM(mem))
|
||||
//#define PSXMs16(mem) (*(s16*)_PSXM(mem))
|
||||
//#define PSXMs32(mem) (*(s32*)_PSXM(mem))
|
||||
//#define PSXMu8(mem) (*(u8 *)_PSXM(mem))
|
||||
//#define PSXMu16(mem) (*(u16*)_PSXM(mem))
|
||||
//#define PSXMu32(mem) (*(u32*)_PSXM(mem))
|
||||
|
||||
void psxMemAlloc();
|
||||
void psxMemReset();
|
||||
void psxMemShutdown();
|
||||
|
|
|
@ -73,7 +73,6 @@ int LoadConfig()
|
|||
GetValue("Lang", Config.Lang);
|
||||
GetValuel("Ps2Out", Config.PsxOut);
|
||||
GetValuel("cdvdPrint", Config.cdvdPrint);
|
||||
GetValuel("ThPriority", Config.ThPriority);
|
||||
GetValue("PluginsDir", Config.PluginsDir);
|
||||
GetValue("BiosDir", Config.BiosDir);
|
||||
|
||||
|
@ -144,7 +143,6 @@ void SaveConfig()
|
|||
SetValue("BiosDir", Config.BiosDir);
|
||||
SetValuel("Ps2Out", Config.PsxOut);
|
||||
SetValuel("cdvdPrint", Config.cdvdPrint);
|
||||
SetValuel("ThPriority", Config.ThPriority);
|
||||
|
||||
SetValuel("EnabledCard1", Config.Mcd[0].Enabled);
|
||||
SetValue("Mcd1", Config.Mcd[0].Filename);
|
||||
|
|
|
@ -94,7 +94,7 @@ namespace OpcodeImpl {
|
|||
}
|
||||
|
||||
void MULT1() {
|
||||
s64 temp = (s64)cpuRegs.GPR.r[_Rs_].SL[0] * (s64)cpuRegs.GPR.r[_Rt_].SL[0];
|
||||
s64 temp = (s64)cpuRegs.GPR.r[_Rs_].SL[0] * cpuRegs.GPR.r[_Rt_].SL[0];
|
||||
|
||||
// Sign-extend into 64 bits:
|
||||
cpuRegs.LO.SD[1] = (s32)(temp & 0xffffffff);
|
||||
|
@ -104,11 +104,11 @@ namespace OpcodeImpl {
|
|||
}
|
||||
|
||||
void MULTU1() {
|
||||
u64 tempu = (u64)cpuRegs.GPR.r[_Rs_].UL[0] * (u64)cpuRegs.GPR.r[_Rt_].UL[0];
|
||||
u64 tempu = (u64)cpuRegs.GPR.r[_Rs_].UL[0] * cpuRegs.GPR.r[_Rt_].UL[0];
|
||||
|
||||
// According to docs, sign-extend into 64 bits even though it's an unsigned mult.
|
||||
cpuRegs.LO.UD[1] = (s32)(tempu & 0xffffffff);
|
||||
cpuRegs.HI.UD[1] = (s32)(tempu >> 32);
|
||||
cpuRegs.LO.SD[1] = (s32)(tempu & 0xffffffff);
|
||||
cpuRegs.HI.SD[1] = (s32)(tempu >> 32);
|
||||
|
||||
if (_Rd_) cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.LO.UD[1];
|
||||
}
|
||||
|
@ -120,12 +120,14 @@ namespace OpcodeImpl {
|
|||
}
|
||||
}
|
||||
|
||||
void DIVU1() {
|
||||
if (cpuRegs.GPR.r[_Rt_].UL[0] != 0) {
|
||||
|
||||
void DIVU1()
|
||||
{
|
||||
if (cpuRegs.GPR.r[_Rt_].UL[0] != 0)
|
||||
{
|
||||
// note: DIVU has no sign extension when assigning back to 64 bits
|
||||
cpuRegs.LO.UD[1] = cpuRegs.GPR.r[_Rs_].UL[0] / cpuRegs.GPR.r[_Rt_].UL[0];
|
||||
cpuRegs.HI.UD[1] = cpuRegs.GPR.r[_Rs_].UL[0] % cpuRegs.GPR.r[_Rt_].UL[0];
|
||||
// note 2: reference material strongly disagrees. (air)
|
||||
cpuRegs.LO.SD[1] = (s32)(cpuRegs.GPR.r[_Rs_].UL[0] / cpuRegs.GPR.r[_Rt_].UL[0]);
|
||||
cpuRegs.HI.SD[1] = (s32)(cpuRegs.GPR.r[_Rs_].UL[0] % cpuRegs.GPR.r[_Rt_].UL[0]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
131
pcsx2/Memory.h
131
pcsx2/Memory.h
|
@ -56,10 +56,9 @@ extern u8 *psS; //0.015 mb, scratch pad
|
|||
#define PS2MEM_EROM psER
|
||||
#define PS2MEM_SCRATCH psS
|
||||
|
||||
extern u8 g_RealGSMem[0x2000];
|
||||
extern u8 g_RealGSMem[Ps2MemSize::GSregs];
|
||||
#define PS2MEM_GS g_RealGSMem
|
||||
|
||||
//#define _PSM(mem) (memLUTR[(mem) >> 12] == 0 ? NULL : (void*)(memLUTR[(mem) >> 12] + ((mem) & 0xfff)))
|
||||
#define PSM(mem) (vtlb_GetPhyPtr(mem&0x1fffffff)) //pcsx2 is a competition.The one with most hacks wins :D
|
||||
|
||||
#define psMs8(mem) (*(s8 *)&PS2MEM_BASE[(mem) & 0x1ffffff])
|
||||
|
@ -116,14 +115,14 @@ extern u8 g_RealGSMem[0x2000];
|
|||
#define psSu32(mem) (*(u32*)&PS2MEM_SCRATCH[(mem) & 0x3fff])
|
||||
#define psSu64(mem) (*(u64*)&PS2MEM_SCRATCH[(mem) & 0x3fff])
|
||||
|
||||
#define PSMs8(mem) (*(s8 *)PSM(mem))
|
||||
#define PSMs16(mem) (*(s16*)PSM(mem))
|
||||
#define PSMs32(mem) (*(s32*)PSM(mem))
|
||||
#define PSMs64(mem) (*(s64*)PSM(mem))
|
||||
#define PSMu8(mem) (*(u8 *)PSM(mem))
|
||||
#define PSMu16(mem) (*(u16*)PSM(mem))
|
||||
#define PSMu32(mem) (*(u32*)PSM(mem))
|
||||
#define PSMu64(mem) (*(u64*)PSM(mem))
|
||||
//#define PSMs8(mem) (*(s8 *)PSM(mem))
|
||||
//#define PSMs16(mem) (*(s16*)PSM(mem))
|
||||
//#define PSMs32(mem) (*(s32*)PSM(mem))
|
||||
//#define PSMs64(mem) (*(s64*)PSM(mem))
|
||||
//#define PSMu8(mem) (*(u8 *)PSM(mem))
|
||||
//#define PSMu16(mem) (*(u16*)PSM(mem))
|
||||
//#define PSMu32(mem) (*(u32*)PSM(mem))
|
||||
//#define PSMu64(mem) (*(u64*)PSM(mem))
|
||||
|
||||
extern void memAlloc();
|
||||
extern void memReset(); // clears PS2 ram and loads the bios. Throws Exception::FileNotFound on error.
|
||||
|
@ -143,10 +142,9 @@ extern void mmap_MarkCountedRamPage(void* ptr,u32 vaddr);
|
|||
extern void mmap_ResetBlockTracking();
|
||||
extern void mmap_ClearCpuBlock( uint offset );
|
||||
|
||||
extern void __fastcall memRead8(u32 mem, u8 *out);
|
||||
extern void __fastcall memRead16(u32 mem, u16 *out);
|
||||
extern void __fastcall memRead32(u32 mem, u32 *out);
|
||||
|
||||
#define memRead8 vtlb_memRead8
|
||||
#define memRead16 vtlb_memRead16
|
||||
#define memRead32 vtlb_memRead32
|
||||
#define memRead64 vtlb_memRead64
|
||||
#define memRead128 vtlb_memRead128
|
||||
|
||||
|
@ -168,6 +166,8 @@ extern void __fastcall memRead32(u32 mem, u32 *out);
|
|||
#define _eeMoveMMREGtoR 0&&
|
||||
|
||||
// extra ops
|
||||
// These allow the old unused const versions of various HW accesses to continue to compile.
|
||||
// (code left in for reference purposes, but is not needed by Vtlb)
|
||||
#define _eeWriteConstMem16OP 0&&
|
||||
#define _eeWriteConstMem32OP 0&&
|
||||
|
||||
|
@ -186,107 +186,4 @@ extern void __fastcall memRead32(u32 mem, u32 *out);
|
|||
extern void loadBiosRom( const char *ext, u8 *dest, long maxSize );
|
||||
extern u16 ba0R16(u32 mem);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// The rest of this header contains the old VM version of the Memory.h API.
|
||||
// Left in for references purposes.
|
||||
|
||||
#ifdef PCSX2_VIRTUAL_MEM
|
||||
|
||||
#define PS2MEM_BASE_ 0x15000000
|
||||
#define PS2MEM_PSX_ (PS2MEM_BASE_+0x1c000000)
|
||||
|
||||
#ifdef _WIN32
|
||||
struct PSMEMORYMAP
|
||||
{
|
||||
uptr* aPFNs, *aVFNs;
|
||||
};
|
||||
#endif
|
||||
|
||||
#define TRANSFORM_ADDR(memaddr) ( ((u32)(memaddr)>=0x40000000) ? ((memaddr)&~0xa0000000) : (memaddr) )
|
||||
|
||||
//new memory model
|
||||
#define PS2MEM_BASE ((u8*)PS2MEM_BASE_)
|
||||
#define PS2MEM_HW ((u8*)((u32)PS2MEM_BASE+0x10000000))
|
||||
#define PS2MEM_ROM ((u8*)((u32)PS2MEM_BASE+0x1fc00000))
|
||||
#define PS2MEM_ROM1 ((u8*)((u32)PS2MEM_BASE+0x1e000000))
|
||||
#define PS2MEM_ROM2 ((u8*)((u32)PS2MEM_BASE+0x1e400000))
|
||||
#define PS2MEM_EROM ((u8*)((u32)PS2MEM_BASE+0x1e040000))
|
||||
#define PS2MEM_PSX ((u8*)PS2MEM_PSX_)
|
||||
#define PS2MEM_SCRATCH ((u8*)((u32)PS2MEM_BASE+0x50000000))
|
||||
#define PS2MEM_VU0MICRO ((u8*)((u32)PS2MEM_BASE+0x11000000))
|
||||
#define PS2MEM_VU0MEM ((u8*)((u32)PS2MEM_BASE+0x11004000))
|
||||
#define PS2MEM_VU1MICRO ((u8*)((u32)PS2MEM_BASE+0x11008000))
|
||||
#define PS2MEM_VU1MEM ((u8*)((u32)PS2MEM_BASE+0x1100c000))
|
||||
|
||||
// function for mapping memory
|
||||
#define PS2MEM_PSXHW ((u8*)((u32)PS2MEM_BASE+0x1f800000))
|
||||
//#define PS2MEM_PSXHW2 ((u8*)((u32)PS2MEM_BASE+0x1fa00000))
|
||||
#define PS2MEM_PSXHW4 ((u8*)((u32)PS2MEM_BASE+0x1f400000))
|
||||
#define PS2MEM_GS ((u8*)((u32)PS2MEM_BASE+0x12000000))
|
||||
#define PS2MEM_DEV9 ((u8*)((u32)PS2MEM_BASE+0x14000000))
|
||||
#define PS2MEM_SPU2 ((u8*)((u32)PS2MEM_BASE+0x1f900000))
|
||||
#define PS2MEM_SPU2_ ((u8*)((u32)PS2MEM_BASE+0x1f000000)) // ?
|
||||
#define PS2MEM_B80 ((u8*)((u32)PS2MEM_BASE+0x18000000))
|
||||
#define PS2MEM_BA0 ((u8*)((u32)PS2MEM_BASE+0x1a000000))
|
||||
|
||||
#define PSM(mem) (PS2MEM_BASE + TRANSFORM_ADDR(mem))
|
||||
|
||||
int __fastcall memRead8(u32 mem, u8 *out);
|
||||
int __fastcall memRead8RS(u32 mem, u64 *out);
|
||||
int __fastcall memRead8RU(u32 mem, u64 *out);
|
||||
int __fastcall memRead16(u32 mem, u16 *out);
|
||||
int __fastcall memRead16RS(u32 mem, u64 *out);
|
||||
int __fastcall memRead16RU(u32 mem, u64 *out);
|
||||
int __fastcall memRead32(u32 mem, u32 *out);
|
||||
int __fastcall memRead32RS(u32 mem, u64 *out);
|
||||
int __fastcall memRead32RU(u32 mem, u64 *out);
|
||||
int __fastcall memRead64(u32 mem, u64 *out);
|
||||
int __fastcall memRead128(u32 mem, u64 *out);
|
||||
void __fastcall memWrite8 (u32 mem, u8 value);
|
||||
void __fastcall memWrite16(u32 mem, u16 value);
|
||||
void __fastcall memWrite32(u32 mem, u32 value);
|
||||
void __fastcall memWrite64(u32 mem, const u64 *value);
|
||||
void __fastcall memWrite128(u32 mem, const u64 *value);
|
||||
|
||||
// recMemConstRead8, recMemConstRead16, recMemConstRead32 return 1 if a call was made, 0 otherwise
|
||||
u8 recMemRead8();
|
||||
u16 recMemRead16();
|
||||
u32 recMemRead32();
|
||||
void recMemRead64(u64 *out);
|
||||
void recMemRead128(u64 *out);
|
||||
|
||||
void recMemWrite8();
|
||||
void recMemWrite16();
|
||||
void recMemWrite32();
|
||||
void recMemWrite64();
|
||||
void recMemWrite128();
|
||||
|
||||
void _eeReadConstMem8(int mmreg, u32 mem, int sign);
|
||||
void _eeReadConstMem16(int mmreg, u32 mem, int sign);
|
||||
void _eeReadConstMem32(int mmreg, u32 mem);
|
||||
void _eeReadConstMem128(int mmreg, u32 mem);
|
||||
void _eeWriteConstMem8(u32 mem, int mmreg);
|
||||
void _eeWriteConstMem16(u32 mem, int mmreg);
|
||||
void _eeWriteConstMem32(u32 mem, int mmreg);
|
||||
void _eeWriteConstMem64(u32 mem, int mmreg);
|
||||
void _eeWriteConstMem128(u32 mem, int mmreg);
|
||||
void _eeMoveMMREGtoR(int to, int mmreg);
|
||||
|
||||
// extra ops
|
||||
void _eeWriteConstMem16OP(u32 mem, int mmreg, int op);
|
||||
void _eeWriteConstMem32OP(u32 mem, int mmreg, int op);
|
||||
|
||||
int recMemConstRead8(u32 x86reg, u32 mem, u32 sign);
|
||||
int recMemConstRead16(u32 x86reg, u32 mem, u32 sign);
|
||||
int recMemConstRead32(u32 x86reg, u32 mem);
|
||||
void recMemConstRead64(u32 mem, int mmreg);
|
||||
void recMemConstRead128(u32 mem, int xmmreg);
|
||||
|
||||
int recMemConstWrite8(u32 mem, int mmreg);
|
||||
int recMemConstWrite16(u32 mem, int mmreg);
|
||||
int recMemConstWrite32(u32 mem, int mmreg);
|
||||
int recMemConstWrite64(u32 mem, int mmreg);
|
||||
int recMemConstWrite128(u32 mem, int xmmreg);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -154,7 +154,6 @@ public:
|
|||
int Cdda;
|
||||
int Mdec;
|
||||
int Patch;
|
||||
int ThPriority;
|
||||
int CustomFps;
|
||||
int Hacks;
|
||||
int GameFixes;
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
//
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#define _PC_ // disables MIPS opcode macros.
|
||||
|
||||
#include "PsxCommon.h"
|
||||
#include "Paths.h"
|
||||
#include "Patch.h"
|
||||
|
@ -133,13 +135,13 @@ void handle_extended_t( IniPatch *p)
|
|||
else switch (PrevCheatType)
|
||||
{
|
||||
case 0x3040: // vvvvvvvv 00000000 Inc
|
||||
memRead32(PrevCheataddr,&u32Val);
|
||||
u32Val = memRead32(PrevCheataddr);
|
||||
memWrite32(PrevCheataddr, u32Val+(p->addr));
|
||||
PrevCheatType = 0;
|
||||
break;
|
||||
|
||||
case 0x3050: // vvvvvvvv 00000000 Dec
|
||||
memRead32(PrevCheataddr,&u32Val);
|
||||
u32Val = memRead32(PrevCheataddr);
|
||||
memWrite32(PrevCheataddr, u32Val-(p->addr));
|
||||
PrevCheatType = 0;
|
||||
break;
|
||||
|
@ -155,7 +157,7 @@ void handle_extended_t( IniPatch *p)
|
|||
case 0x5000: // dddddddd iiiiiiii
|
||||
for(i=0;i<IterationCount;i++)
|
||||
{
|
||||
memRead8(PrevCheataddr+i,&u8Val);
|
||||
u8Val = memRead8(PrevCheataddr+i);
|
||||
memWrite8(((u32)p->data)+i,u8Val);
|
||||
}
|
||||
PrevCheatType = 0;
|
||||
|
@ -167,7 +169,7 @@ void handle_extended_t( IniPatch *p)
|
|||
|
||||
// Read first pointer
|
||||
LastType = ((u32)p->addr&0x000F0000)/0x10000;
|
||||
memRead32(PrevCheataddr,&u32Val);
|
||||
u32Val = memRead32(PrevCheataddr);
|
||||
PrevCheataddr = u32Val+(u32)p->data;
|
||||
IterationCount--;
|
||||
|
||||
|
@ -182,7 +184,7 @@ void handle_extended_t( IniPatch *p)
|
|||
|
||||
case 0x6001: // 000Xnnnn iiiiiiii
|
||||
// Read first pointer
|
||||
memRead32(PrevCheataddr,&u32Val);
|
||||
u32Val = memRead32(PrevCheataddr);
|
||||
PrevCheataddr =u32Val+(u32)p->addr;
|
||||
IterationCount--;
|
||||
|
||||
|
@ -194,7 +196,7 @@ void handle_extended_t( IniPatch *p)
|
|||
}
|
||||
else
|
||||
{
|
||||
memRead32(PrevCheataddr,&u32Val);
|
||||
u32Val = memRead32(PrevCheataddr);
|
||||
PrevCheataddr =u32Val+(u32)p->data;
|
||||
IterationCount--;
|
||||
|
||||
|
@ -223,25 +225,25 @@ void handle_extended_t( IniPatch *p)
|
|||
}
|
||||
else if ((p->addr&0xFFFF0000) == 0x30000000) // 300000vv 0aaaaaaa Inc
|
||||
{
|
||||
memRead8((u32)p->data,&u8Val);
|
||||
u8Val = memRead8((u32)p->data);
|
||||
memWrite8((u32)p->data, u8Val+(p->addr&0x000000FF));
|
||||
PrevCheatType = 0;
|
||||
}
|
||||
else if ((p->addr&0xFFFF0000) == 0x30100000) // 301000vv 0aaaaaaa Dec
|
||||
{
|
||||
memRead8((u32)p->data,&u8Val);
|
||||
u8Val = memRead8((u32)p->data);
|
||||
memWrite8((u32)p->data, u8Val-(p->addr&0x000000FF));
|
||||
PrevCheatType = 0;
|
||||
}
|
||||
else if ((p->addr&0xFFFF0000) == 0x30200000) // 3020vvvv 0aaaaaaa Inc
|
||||
{
|
||||
memRead16((u32)p->data,&u16Val);
|
||||
u16Val = memRead16((u32)p->data);
|
||||
memWrite16((u32)p->data, u16Val+(p->addr&0x0000FFFF));
|
||||
PrevCheatType = 0;
|
||||
}
|
||||
else if ((p->addr&0xFFFF0000) == 0x30300000) // 3030vvvv 0aaaaaaa Dec
|
||||
{
|
||||
memRead16((u32)p->data,&u16Val);
|
||||
u16Val = memRead16((u32)p->data);
|
||||
memWrite16((u32)p->data, u16Val-(p->addr&0x0000FFFF));
|
||||
PrevCheatType = 0;
|
||||
}
|
||||
|
@ -279,32 +281,32 @@ void handle_extended_t( IniPatch *p)
|
|||
{
|
||||
if ((p->data&0x00F00000) == 0x00000000) // 7aaaaaaa 000000vv
|
||||
{
|
||||
memRead8((u32)p->addr&0x0FFFFFFF,&u8Val);
|
||||
u8Val = memRead8((u32)p->addr&0x0FFFFFFF);
|
||||
memWrite8((u32)p->addr&0x0FFFFFFF,(u8)(u8Val|(p->data&0x000000FF)));
|
||||
}
|
||||
else if ((p->data&0x00F00000) == 0x00100000) // 7aaaaaaa 0010vvvv
|
||||
{
|
||||
memRead16((u32)p->addr&0x0FFFFFFF,&u16Val);
|
||||
u16Val = memRead16((u32)p->addr&0x0FFFFFFF);
|
||||
memWrite16((u32)p->addr&0x0FFFFFFF,(u16)(u16Val|(p->data&0x0000FFFF)));
|
||||
}
|
||||
else if ((p->data&0x00F00000) == 0x00200000) // 7aaaaaaa 002000vv
|
||||
{
|
||||
memRead8((u32)p->addr&0x0FFFFFFF,&u8Val);
|
||||
u8Val = memRead8((u32)p->addr&0x0FFFFFFF);
|
||||
memWrite8((u32)p->addr&0x0FFFFFFF,(u8)(u8Val&(p->data&0x000000FF)));
|
||||
}
|
||||
else if ((p->data&0x00F00000) == 0x00300000) // 7aaaaaaa 0030vvvv
|
||||
{
|
||||
memRead16((u32)p->addr&0x0FFFFFFF,&u16Val);
|
||||
u16Val = memRead16((u32)p->addr&0x0FFFFFFF);
|
||||
memWrite16((u32)p->addr&0x0FFFFFFF,(u16)(u16Val&(p->data&0x0000FFFF)));
|
||||
}
|
||||
else if ((p->data&0x00F00000) == 0x00400000) // 7aaaaaaa 004000vv
|
||||
{
|
||||
memRead8((u32)p->addr&0x0FFFFFFF,&u8Val);
|
||||
u8Val = memRead8((u32)p->addr&0x0FFFFFFF);
|
||||
memWrite8((u32)p->addr&0x0FFFFFFF,(u8)(u8Val^(p->data&0x000000FF)));
|
||||
}
|
||||
else if ((p->data&0x00F00000) == 0x00500000) // 7aaaaaaa 0050vvvv
|
||||
{
|
||||
memRead16((u32)p->addr&0x0FFFFFFF,&u16Val);
|
||||
u16Val = memRead16((u32)p->addr&0x0FFFFFFF);
|
||||
memWrite16((u32)p->addr&0x0FFFFFFF,(u16)(u16Val^(p->data&0x0000FFFF)));
|
||||
}
|
||||
}
|
||||
|
@ -315,7 +317,7 @@ void handle_extended_t( IniPatch *p)
|
|||
(((u32)p->data & 0xFFFF0000)==0x00200000) ||
|
||||
(((u32)p->data & 0xFFFF0000)==0x00300000))
|
||||
{
|
||||
memRead16((u32)p->addr&0x0FFFFFFF,&u16Val);
|
||||
u16Val = memRead16((u32)p->addr&0x0FFFFFFF);
|
||||
if (u16Val != (0x0000FFFF&(u32)p->data)) SkipCount = 1;
|
||||
PrevCheatType= 0;
|
||||
}
|
||||
|
@ -327,7 +329,7 @@ void handle_extended_t( IniPatch *p)
|
|||
(((u32)p->data&0xF0000000)==0x20000000) ||
|
||||
(((u32)p->data&0xF0000000)==0x30000000))
|
||||
{
|
||||
memRead16((u32)p->data&0x0FFFFFFF,&u16Val);
|
||||
u16Val = memRead16((u32)p->data&0x0FFFFFFF);
|
||||
if (u16Val != (0x0000FFFF&(u32)p->addr)) SkipCount = ((u32)p->addr&0xFFF0000)/0x10000;
|
||||
PrevCheatType= 0;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,9 @@ extern int cdOpenCase;
|
|||
#define PSXCLK (36864000ULL) /* 36.864 Mhz */
|
||||
|
||||
#include "Plugins.h"
|
||||
#include "Misc.h"
|
||||
#include "SaveState.h"
|
||||
|
||||
#include "R3000A.h"
|
||||
#include "IopMem.h"
|
||||
#include "IopHw.h"
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include "PsxCommon.h"
|
||||
#include "Misc.h"
|
||||
|
||||
#include "R5900.h"
|
||||
|
||||
using namespace R3000A;
|
||||
|
||||
R3000Acpu *psxCpu;
|
||||
|
|
|
@ -37,13 +37,13 @@
|
|||
|
||||
#include "Paths.h"
|
||||
|
||||
#include "R5900Exceptions.h"
|
||||
|
||||
using namespace R5900; // for R5900 disasm tools
|
||||
|
||||
s32 EEsCycle; // used to sync the IOP to the EE
|
||||
u32 EEoCycle;
|
||||
|
||||
//static int inter;
|
||||
|
||||
PCSX2_ALIGNED16(cpuRegisters cpuRegs);
|
||||
PCSX2_ALIGNED16(fpuRegisters fpuRegs);
|
||||
PCSX2_ALIGNED16(tlbs tlb[48]);
|
||||
|
@ -56,6 +56,8 @@ static uint eeWaitCycles = 1024;
|
|||
|
||||
bool eeEventTestIsActive = false;
|
||||
|
||||
R5900Exception::BaseExcept::~BaseExcept() {}
|
||||
|
||||
// A run-once procedure for initializing the emulation state.
|
||||
// Can be done anytime after allocating memory, and before calling Cpu->Execute().
|
||||
// Multiple calls to this function are automatically ignored.
|
||||
|
|
|
@ -100,9 +100,9 @@ struct cpuRegisters {
|
|||
GPR_reg LO; // hi & log 128bit wide
|
||||
CP0regs CP0; // is COP0 32bit?
|
||||
u32 sa; // shift amount (32bit), needs to be 16 byte aligned
|
||||
u32 constzero; // always 0, for MFSA
|
||||
u32 IsDelaySlot; // set true when the current instruction is a delay slot.
|
||||
u32 pc; // Program counter, when changing offset in struct, check iR5900-X.S to make sure offset is correct
|
||||
u32 code; // The instruction
|
||||
u32 code; // current instruction
|
||||
PERFregs PERF;
|
||||
u32 eCycle[32];
|
||||
u32 sCycle[32]; // for internal counters
|
||||
|
@ -110,7 +110,7 @@ struct cpuRegisters {
|
|||
u32 interrupt;
|
||||
int branch;
|
||||
int opmode; // operating mode
|
||||
u32 tempcycles;
|
||||
u32 tempcycles;
|
||||
};
|
||||
|
||||
// used for optimization
|
||||
|
@ -184,9 +184,10 @@ struct tlbs
|
|||
#define _Opcode_ (cpuRegs.code >> 26 )
|
||||
|
||||
#define _JumpTarget_ ((_Target_ << 2) + (_PC_ & 0xf0000000)) // Calculates the target during a jump instruction
|
||||
#define _BranchTarget_ (((s32)(s16)_Im_ * 4) + _PC_) // Calculates the target during a branch instruction
|
||||
#define _BranchTarget_ (((s32)(s16)_Im_ * 4) + _PC_) // Calculates the target during a branch instruction
|
||||
#define _TrapCode_ ((u16)cpuRegs.code >> 6) // error code for non-immediate trap instructions.
|
||||
|
||||
#define _SetLink(x) cpuRegs.GPR.r[x].UD[0] = _PC_ + 4; // Sets the return address in the link register
|
||||
#define _SetLink(x) (cpuRegs.GPR.r[x].UD[0] = _PC_ + 4) // Sets the return address in the link register
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -0,0 +1,177 @@
|
|||
/* Pcsx2 - Pc Ps2 Emulator
|
||||
* Copyright (C) 2002-2009 Pcsx2 Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef _R5900_EXCEPTIONS_H_
|
||||
#define _R5900_EXCEPTIONS_H_
|
||||
|
||||
namespace R5900Exception
|
||||
{
|
||||
using Exception::Ps2Generic;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Abstract base class for R5900 exceptions; contains the cpuRegs instance at the
|
||||
// time the exception is raised.
|
||||
//
|
||||
class BaseExcept : public Ps2Generic
|
||||
{
|
||||
public:
|
||||
const cpuRegisters cpuState;
|
||||
|
||||
public:
|
||||
virtual ~BaseExcept() throw()=0;
|
||||
|
||||
explicit BaseExcept( const std::string& msg ) :
|
||||
Exception::Ps2Generic( "(EE) " + msg ),
|
||||
cpuState( cpuRegs )
|
||||
{
|
||||
}
|
||||
|
||||
u32 GetPc() const { return cpuState.pc; }
|
||||
bool IsDelaySlot() const { return !!cpuState.IsDelaySlot; }
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
class AddressError : public BaseExcept
|
||||
{
|
||||
public:
|
||||
const bool OnWrite;
|
||||
const u32 Address;
|
||||
|
||||
public:
|
||||
virtual ~AddressError() throw() {}
|
||||
|
||||
explicit AddressError( u32 ps2addr, bool onWrite ) :
|
||||
BaseExcept( fmt_string( "Address error, addr=0x%x [%s]", ps2addr, onWrite ? "store" : "load" ) ),
|
||||
OnWrite( onWrite ),
|
||||
Address( ps2addr )
|
||||
{}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
class TLBMiss : public BaseExcept
|
||||
{
|
||||
public:
|
||||
const bool OnWrite;
|
||||
const u32 Address;
|
||||
|
||||
public:
|
||||
virtual ~TLBMiss() throw() {}
|
||||
|
||||
explicit TLBMiss( u32 ps2addr, bool onWrite ) :
|
||||
BaseExcept( fmt_string( "Tlb Miss, addr=0x%x [%s]", ps2addr, onWrite ? "store" : "load" ) ),
|
||||
OnWrite( onWrite ),
|
||||
Address( ps2addr )
|
||||
{}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
class BusError : public BaseExcept
|
||||
{
|
||||
public:
|
||||
const bool OnWrite;
|
||||
const u32 Address;
|
||||
|
||||
public:
|
||||
virtual ~BusError() throw() {}
|
||||
|
||||
//
|
||||
explicit BusError( u32 ps2addr, bool onWrite ) :
|
||||
BaseExcept( fmt_string( "Bus Error, addr=0x%x [%s]", ps2addr, onWrite ? "store" : "load" ) ),
|
||||
OnWrite( onWrite ),
|
||||
Address( ps2addr )
|
||||
{}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
class SystemCall : public BaseExcept
|
||||
{
|
||||
public:
|
||||
virtual ~SystemCall() throw() {}
|
||||
|
||||
explicit SystemCall() :
|
||||
BaseExcept( "SystemCall [SYSCALL]" )
|
||||
{}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
class Trap : public BaseExcept
|
||||
{
|
||||
public:
|
||||
const u16 TrapCode;
|
||||
|
||||
public:
|
||||
virtual ~Trap() throw() {}
|
||||
|
||||
// Generates a trap for immediate-style Trap opcodes
|
||||
explicit Trap() :
|
||||
BaseExcept( "Trap" ),
|
||||
TrapCode( 0 )
|
||||
{}
|
||||
|
||||
// Generates a trap for register-style Trap instructions, which contain an
|
||||
// error code in the opcode
|
||||
explicit Trap( u16 trapcode ) :
|
||||
BaseExcept( "Trap" ),
|
||||
TrapCode( trapcode )
|
||||
{}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
class Break : public BaseExcept
|
||||
{
|
||||
public:
|
||||
virtual ~Break() throw() {}
|
||||
|
||||
explicit Break() :
|
||||
BaseExcept( "Break Instruction" )
|
||||
{}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
class Overflow : public BaseExcept
|
||||
{
|
||||
public:
|
||||
virtual ~Overflow() throw() {}
|
||||
|
||||
explicit Overflow() :
|
||||
BaseExcept( "Overflow" )
|
||||
{}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
class DebugBreakpoint : public BaseExcept
|
||||
{
|
||||
public:
|
||||
virtual ~DebugBreakpoint() throw() {}
|
||||
|
||||
explicit DebugBreakpoint() :
|
||||
BaseExcept( "Debug Breakpoint" )
|
||||
{}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -21,9 +21,45 @@
|
|||
#include "Common.h"
|
||||
#include "R5900.h"
|
||||
#include "R5900OpcodeTables.h"
|
||||
#include "R5900Exceptions.h"
|
||||
|
||||
#include <float.h>
|
||||
|
||||
static __forceinline s64 _add64_Overflow( s64 x, s64 y )
|
||||
{
|
||||
const s64 result = x + y;
|
||||
|
||||
// Let's all give gigaherz a big round of applause for finding this gem,
|
||||
// which apparently works, and generates compact/fast x86 code too (the
|
||||
// other method below is like 5-10 times slower).
|
||||
|
||||
if( ((~(x^y))&(x^result)) < 0 )
|
||||
throw R5900Exception::Overflow();
|
||||
|
||||
// the not-as-fast style!
|
||||
//if( ((x >= 0) && (y >= 0) && (result < 0)) ||
|
||||
// ((x < 0) && (y < 0) && (result >= 0)) )
|
||||
// throw R5900Exception::Overflow();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static __forceinline s64 _add32_Overflow( s32 x, s32 y )
|
||||
{
|
||||
GPR_reg64 result; result.SD[0] = (s64)x + y;
|
||||
|
||||
// This 32bit method can rely on the MIPS documented method of checking for
|
||||
// overflow, whichs imply compares bit 32 (rightmost bit of the upper word),
|
||||
// against bit 31 (leftmost of the lower word).
|
||||
|
||||
// If bit32 != bit31 then we have an overflow.
|
||||
if( (result.UL[0]>>31) != (result.UL[1] & 1) )
|
||||
throw R5900Exception::Overflow();
|
||||
|
||||
return result.SD[0];
|
||||
}
|
||||
|
||||
|
||||
namespace R5900
|
||||
{
|
||||
const OPCODE& GetCurrentInstruction()
|
||||
|
@ -106,84 +142,162 @@ void MMI_Unknown() { Console::Notice("Unknown MMI opcode called"); }
|
|||
void COP0_Unknown() { Console::Notice("Unknown COP0 opcode called"); }
|
||||
void COP1_Unknown() { Console::Notice("Unknown FPU/COP1 opcode called"); }
|
||||
|
||||
|
||||
|
||||
/*********************************************************
|
||||
* Arithmetic with immediate operand *
|
||||
* Format: OP rt, rs, immediate *
|
||||
*********************************************************/
|
||||
void ADDI() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].SL[0] + _Imm_; }// Rt = Rs + Im signed!!!!
|
||||
void ADDIU() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].SL[0] + _Imm_; }// Rt = Rs + Im signed !!!
|
||||
void DADDI() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] + _Imm_; }// Rt = Rs + Im
|
||||
void DADDIU() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] + _Imm_; }// Rt = Rs + Im
|
||||
|
||||
// Implementation Notes:
|
||||
// * It is important that instructions perform overflow checks prior to shortcutting on
|
||||
// the zero register (when it is used as a destination). Overflow exceptions are still
|
||||
// handled even though the result is discarded.
|
||||
|
||||
// Rt = Rs + Im signed [exception on overflow]
|
||||
void ADDI()
|
||||
{
|
||||
s64 result = _add32_Overflow( cpuRegs.GPR.r[_Rs_].SD[0], _Imm_ );
|
||||
if (!_Rt_) return;
|
||||
cpuRegs.GPR.r[_Rt_].SD[0] = result;
|
||||
}
|
||||
|
||||
// Rt = Rs + Im signed !!! [overflow ignored]
|
||||
// This instruction is effectively identical to ADDI. It is not a true unsigned operation,
|
||||
// but rather it is a signed operation that ignores overflows.
|
||||
void ADDIU()
|
||||
{
|
||||
if (!_Rt_) return;
|
||||
cpuRegs.GPR.r[_Rt_].SD[0] = cpuRegs.GPR.r[_Rs_].SL[0] + _Imm_;
|
||||
}
|
||||
|
||||
// Rt = Rs + Im [exception on overflow]
|
||||
// This is the full 64 bit version of ADDI. Overflow occurs at 64 bits instead
|
||||
// of at 32 bits.
|
||||
void DADDI()
|
||||
{
|
||||
s64 result = _add64_Overflow( cpuRegs.GPR.r[_Rs_].SD[0], _Imm_ );
|
||||
if (!_Rt_) return;
|
||||
cpuRegs.GPR.r[_Rt_].SD[0] = result;
|
||||
}
|
||||
|
||||
// Rt = Rs + Im [overflow ignored]
|
||||
// This instruction is effectively identical to DADDI. It is not a true unsigned operation,
|
||||
// but rather it is a signed operation that ignores overflows.
|
||||
void DADDIU()
|
||||
{
|
||||
if (!_Rt_) return;
|
||||
cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] + _Imm_;
|
||||
}
|
||||
void ANDI() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] & (u64)_ImmU_; } // Rt = Rs And Im (zero-extended)
|
||||
void ORI() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] | (u64)_ImmU_; } // Rt = Rs Or Im (zero-extended)
|
||||
void XORI() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] ^ (u64)_ImmU_; } // Rt = Rs Xor Im (zero-extended)
|
||||
void SLTI() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] < (s64)(_Imm_); } // Rt = Rs < Im (signed)
|
||||
void SLTIU() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] < (u64)(_Imm_); } // Rt = Rs < Im (unsigned)
|
||||
void SLTI() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = (cpuRegs.GPR.r[_Rs_].SD[0] < (s64)(_Imm_)) ? 1 : 0; } // Rt = Rs < Im (signed)
|
||||
void SLTIU() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = (cpuRegs.GPR.r[_Rs_].UD[0] < (u64)(_Imm_)) ? 1 : 0; } // Rt = Rs < Im (unsigned)
|
||||
|
||||
/*********************************************************
|
||||
* Register arithmetic *
|
||||
* Format: OP rd, rs, rt *
|
||||
*********************************************************/
|
||||
void ADD() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SL[0] + cpuRegs.GPR.r[_Rt_].SL[0];} // Rd = Rs + Rt (Exception on Integer Overflow)
|
||||
|
||||
// Rd = Rs + Rt (Exception on Integer Overflow)
|
||||
void ADD()
|
||||
{
|
||||
s64 result = _add32_Overflow( cpuRegs.GPR.r[_Rs_].SD[0], cpuRegs.GPR.r[_Rt_].SD[0] );
|
||||
if (!_Rd_) return;
|
||||
cpuRegs.GPR.r[_Rd_].SD[0] = result;
|
||||
}
|
||||
|
||||
void DADD()
|
||||
{
|
||||
s64 result = _add64_Overflow( cpuRegs.GPR.r[_Rs_].SD[0], cpuRegs.GPR.r[_Rt_].SD[0] );
|
||||
if (!_Rd_) return;
|
||||
cpuRegs.GPR.r[_Rd_].SD[0] = result;
|
||||
}
|
||||
|
||||
// Rd = Rs - Rt (Exception on Integer Overflow)
|
||||
void SUB()
|
||||
{
|
||||
s64 result = _add32_Overflow( cpuRegs.GPR.r[_Rs_].SD[0], -cpuRegs.GPR.r[_Rt_].SD[0] );
|
||||
if (!_Rd_) return;
|
||||
cpuRegs.GPR.r[_Rd_].SD[0] = result;
|
||||
}
|
||||
|
||||
// Rd = Rs - Rt (Exception on Integer Overflow)
|
||||
void DSUB()
|
||||
{
|
||||
s64 result = _add64_Overflow( cpuRegs.GPR.r[_Rs_].SD[0], -cpuRegs.GPR.r[_Rt_].SD[0] );
|
||||
if (!_Rd_) return;
|
||||
cpuRegs.GPR.r[_Rd_].SD[0] = result;
|
||||
}
|
||||
|
||||
void ADDU() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SL[0] + cpuRegs.GPR.r[_Rt_].SL[0];} // Rd = Rs + Rt
|
||||
void DADD() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] + cpuRegs.GPR.r[_Rt_].SD[0]; }
|
||||
void DADDU() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] + cpuRegs.GPR.r[_Rt_].SD[0]; }
|
||||
void SUB() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SL[0] - cpuRegs.GPR.r[_Rt_].SL[0];} // Rd = Rs - Rt (Exception on Integer Overflow)
|
||||
void SUBU() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SL[0] - cpuRegs.GPR.r[_Rt_].SL[0]; } // Rd = Rs - Rt
|
||||
void DSUB() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] - cpuRegs.GPR.r[_Rt_].SD[0];}
|
||||
void DSUBU() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] - cpuRegs.GPR.r[_Rt_].SD[0]; }
|
||||
void AND() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] & cpuRegs.GPR.r[_Rt_].UD[0]; } // Rd = Rs And Rt
|
||||
void OR() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] | cpuRegs.GPR.r[_Rt_].UD[0]; } // Rd = Rs Or Rt
|
||||
void XOR() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] ^ cpuRegs.GPR.r[_Rt_].UD[0]; } // Rd = Rs Xor Rt
|
||||
void NOR() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] =~(cpuRegs.GPR.r[_Rs_].UD[0] | cpuRegs.GPR.r[_Rt_].UD[0]); }// Rd = Rs Nor Rt
|
||||
void SLT() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] < cpuRegs.GPR.r[_Rt_].SD[0]; } // Rd = Rs < Rt (signed)
|
||||
void SLTU() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] < cpuRegs.GPR.r[_Rt_].UD[0]; } // Rd = Rs < Rt (unsigned)
|
||||
void SLT() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (cpuRegs.GPR.r[_Rs_].SD[0] < cpuRegs.GPR.r[_Rt_].SD[0]) ? 1 : 0; } // Rd = Rs < Rt (signed)
|
||||
void SLTU() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (cpuRegs.GPR.r[_Rs_].UD[0] < cpuRegs.GPR.r[_Rt_].UD[0]) ? 1 : 0; } // Rd = Rs < Rt (unsigned)
|
||||
|
||||
/*********************************************************
|
||||
* Register mult/div & Register trap logic *
|
||||
* Format: OP rs, rt *
|
||||
*********************************************************/
|
||||
void DIV() {
|
||||
if (cpuRegs.GPR.r[_Rt_].SL[0] != 0) {
|
||||
|
||||
// Result is stored in HI/LO [no arithmetic exceptions]
|
||||
void DIV()
|
||||
{
|
||||
if (cpuRegs.GPR.r[_Rt_].SL[0] != 0)
|
||||
{
|
||||
cpuRegs.LO.SD[0] = cpuRegs.GPR.r[_Rs_].SL[0] / cpuRegs.GPR.r[_Rt_].SL[0];
|
||||
cpuRegs.HI.SD[0] = cpuRegs.GPR.r[_Rs_].SL[0] % cpuRegs.GPR.r[_Rt_].SL[0];
|
||||
}
|
||||
}
|
||||
|
||||
void DIVU() {
|
||||
if (cpuRegs.GPR.r[_Rt_].UL[0] != 0) {
|
||||
|
||||
// Result is stored in HI/LO [no arithmetic exceptions]
|
||||
void DIVU()
|
||||
{
|
||||
if (cpuRegs.GPR.r[_Rt_].UL[0] != 0)
|
||||
{
|
||||
// note: DIVU has no sign extension when assigning back to 64 bits
|
||||
cpuRegs.LO.SD[0] = cpuRegs.GPR.r[_Rs_].UL[0] / cpuRegs.GPR.r[_Rt_].UL[0];
|
||||
cpuRegs.HI.SD[0] = cpuRegs.GPR.r[_Rs_].UL[0] % cpuRegs.GPR.r[_Rt_].UL[0];
|
||||
// note 2: reference material strongly disagrees. (air)
|
||||
cpuRegs.LO.SD[0] = (s32)(cpuRegs.GPR.r[_Rs_].UL[0] / cpuRegs.GPR.r[_Rt_].UL[0]);
|
||||
cpuRegs.HI.SD[0] = (s32)(cpuRegs.GPR.r[_Rs_].UL[0] % cpuRegs.GPR.r[_Rt_].UL[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void MULT() { //different in ps2...
|
||||
s64 res = (s64)cpuRegs.GPR.r[_Rs_].SL[0] * (s64)cpuRegs.GPR.r[_Rt_].SL[0];
|
||||
// Result is written to both HI/LO and to the _Rd_ (Lo only)
|
||||
void MULT()
|
||||
{
|
||||
s64 res = (s64)cpuRegs.GPR.r[_Rs_].SL[0] * cpuRegs.GPR.r[_Rt_].SL[0];
|
||||
|
||||
// Sign-extend into 64 bits:
|
||||
cpuRegs.LO.UD[0] = (s32)(res & 0xffffffff);
|
||||
cpuRegs.HI.UD[0] = (s32)(res >> 32);
|
||||
cpuRegs.LO.SD[0] = (s32)(res & 0xffffffff);
|
||||
cpuRegs.HI.SD[0] = (s32)(res >> 32);
|
||||
|
||||
if( _Rd_ ) cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.LO.UD[0]; //that is the difference
|
||||
if( _Rd_ ) cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.LO.UD[0];
|
||||
}
|
||||
|
||||
void MULTU() { //different in ps2..
|
||||
u64 res = (u64)cpuRegs.GPR.r[_Rs_].UL[0] * (u64)cpuRegs.GPR.r[_Rt_].UL[0];
|
||||
// Result is written to both HI/LO and to the _Rd_ (Lo only)
|
||||
void MULTU()
|
||||
{
|
||||
u64 res = (u64)cpuRegs.GPR.r[_Rs_].UL[0] * cpuRegs.GPR.r[_Rt_].UL[0];
|
||||
|
||||
// According to docs, sign-extend into 64 bits even though it's an unsigned mult.
|
||||
cpuRegs.LO.UD[0] = (s32)(res & 0xffffffff);
|
||||
cpuRegs.HI.UD[0] = (s32)(res >> 32);
|
||||
// Note: sign-extend into 64 bits even though it's an unsigned mult.
|
||||
cpuRegs.LO.SD[0] = (s32)(res & 0xffffffff);
|
||||
cpuRegs.HI.SD[0] = (s32)(res >> 32);
|
||||
|
||||
if( _Rd_ ) cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.LO.UD[0]; //that is the difference
|
||||
if( _Rd_ ) cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.LO.UD[0];
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
* Load higher 16 bits of the first word in GPR with imm *
|
||||
* Format: OP rt, immediate *
|
||||
*********************************************************/
|
||||
void LUI() {
|
||||
void LUI() {
|
||||
if (!_Rt_) return;
|
||||
cpuRegs.GPR.r[_Rt_].UD[0] = (s32)(cpuRegs.code << 16);
|
||||
}
|
||||
|
@ -207,15 +321,15 @@ void MTLO() { cpuRegs.LO.UD[0] = cpuRegs.GPR.r[_Rs_].UD[0]; } // Lo = Rs
|
|||
* Shift arithmetic with constant shift *
|
||||
* Format: OP rd, rt, sa *
|
||||
*********************************************************/
|
||||
void SRA() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s32)(cpuRegs.GPR.r[_Rt_].SL[0] >> _Sa_); } // Rd = Rt >> sa (arithmetic)
|
||||
void SRL() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s32)(cpuRegs.GPR.r[_Rt_].UL[0] >> _Sa_); } // Rd = Rt >> sa (logical) [sign extend!!]
|
||||
void SLL() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s32)(cpuRegs.GPR.r[_Rt_].UL[0] << _Sa_); } // Rd = Rt << sa
|
||||
void DSLL() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (u64)(cpuRegs.GPR.r[_Rt_].UD[0] << _Sa_); }
|
||||
void DSLL32(){ if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (u64)(cpuRegs.GPR.r[_Rt_].UD[0] << (_Sa_+32));}
|
||||
void SRA() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s32)(cpuRegs.GPR.r[_Rt_].SL[0] >> _Sa_); } // Rd = Rt >> sa (arithmetic)
|
||||
void DSRA() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (u64)(cpuRegs.GPR.r[_Rt_].SD[0] >> _Sa_); }
|
||||
void DSRA32(){ if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (u64)(cpuRegs.GPR.r[_Rt_].SD[0] >> (_Sa_+32));}
|
||||
void SRL() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s32)(cpuRegs.GPR.r[_Rt_].UL[0] >> _Sa_); } // Rd = Rt >> sa (logical)
|
||||
void DSRL() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (u64)(cpuRegs.GPR.r[_Rt_].UD[0] >> _Sa_); }
|
||||
void DSRL32(){ if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (u64)(cpuRegs.GPR.r[_Rt_].UD[0] >> (_Sa_+32));}
|
||||
void DSRA() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = cpuRegs.GPR.r[_Rt_].SD[0] >> _Sa_; }
|
||||
void DSRA32(){ if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = cpuRegs.GPR.r[_Rt_].SD[0] >> (_Sa_+32);}
|
||||
void DSRL() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rt_].UD[0] >> _Sa_; }
|
||||
void DSRL32(){ if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rt_].UD[0] >> (_Sa_+32);}
|
||||
|
||||
/*********************************************************
|
||||
* Shift arithmetic with variant register shift *
|
||||
|
@ -233,86 +347,85 @@ void DSRLV(){ if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (u64)(cpuRegs.GPR.r
|
|||
* Format: OP rt, offset(base) *
|
||||
*********************************************************/
|
||||
|
||||
void LB() {
|
||||
u32 addr;
|
||||
// Implementation Notes Regarding Memory Operations:
|
||||
// * It it 'correct' to do all loads into temp variables, even if the destination GPR
|
||||
// is the zero reg (which nullifies the result). The memory needs to be accessed
|
||||
// regardless so that hardware registers behave as expected (some clear on read) and
|
||||
// so that TLB Misses are handled as expected as well.
|
||||
//
|
||||
// * Low/High varieties of instructions, such as LWL/LWH, do *not* raise Address Error
|
||||
// exceptions, since the lower bits of the address are used to determine the portions
|
||||
// of the address/register operations.
|
||||
|
||||
addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
u8 temp;
|
||||
const u32 rt=_Rt_;
|
||||
|
||||
memRead8(addr, &temp);
|
||||
if(rt!=0)
|
||||
{
|
||||
cpuRegs.GPR.r[rt].UD[0]=(s8)temp;
|
||||
}
|
||||
void LB()
|
||||
{
|
||||
u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
s8 temp = memRead8(addr);
|
||||
|
||||
if (!_Rt_) return;
|
||||
cpuRegs.GPR.r[_Rt_].SD[0] = temp;
|
||||
}
|
||||
|
||||
void LBU() {
|
||||
u32 addr;
|
||||
void LBU()
|
||||
{
|
||||
u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
u8 temp = memRead8(addr);
|
||||
|
||||
addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
u8 temp;
|
||||
const u32 rt=_Rt_;
|
||||
memRead8(addr, &temp);
|
||||
if(rt!=0)
|
||||
{
|
||||
cpuRegs.GPR.r[rt].UD[0]=temp;
|
||||
}
|
||||
if (!_Rt_) return;
|
||||
cpuRegs.GPR.r[_Rt_].UD[0] = temp;
|
||||
}
|
||||
|
||||
void LH() {
|
||||
u32 addr;
|
||||
void LH()
|
||||
{
|
||||
u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
|
||||
addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
u16 temp;
|
||||
const u32 rt=_Rt_;
|
||||
memRead16(addr, &temp);
|
||||
if(rt!=0)
|
||||
{
|
||||
cpuRegs.GPR.r[rt].UD[0]=(s16)temp;
|
||||
}
|
||||
if( addr & 1 )
|
||||
throw R5900Exception::AddressError( addr, false );
|
||||
|
||||
s16 temp = memRead16(addr);
|
||||
|
||||
if (!_Rt_) return;
|
||||
cpuRegs.GPR.r[_Rt_].SD[0] = temp;
|
||||
}
|
||||
|
||||
void LHU() {
|
||||
u32 addr;
|
||||
void LHU()
|
||||
{
|
||||
u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
|
||||
addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
u16 temp;
|
||||
const u32 rt=_Rt_;
|
||||
memRead16(addr, &temp);
|
||||
if(rt!=0)
|
||||
{
|
||||
cpuRegs.GPR.r[rt].UD[0]=temp;
|
||||
}
|
||||
if( addr & 1 )
|
||||
throw R5900Exception::AddressError( addr, false );
|
||||
|
||||
u16 temp = memRead16(addr);
|
||||
|
||||
if (!_Rt_) return;
|
||||
cpuRegs.GPR.r[_Rt_].UD[0] = temp;
|
||||
}
|
||||
|
||||
void LW()
|
||||
{
|
||||
u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
|
||||
void LW() {
|
||||
u32 addr;
|
||||
if( addr & 3 )
|
||||
throw R5900Exception::AddressError( addr, false );
|
||||
|
||||
addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
u32 temp = memRead32(addr);
|
||||
|
||||
u32 temp;
|
||||
const u32 rt=_Rt_;
|
||||
memRead32(addr, &temp);
|
||||
if(rt!=0)
|
||||
{
|
||||
cpuRegs.GPR.r[rt].UD[0]=(s32)temp;
|
||||
}
|
||||
if (!_Rt_) return;
|
||||
cpuRegs.GPR.r[_Rt_].SD[0] = (s32)temp;
|
||||
}
|
||||
|
||||
void LWU() {
|
||||
u32 addr;
|
||||
void LWU()
|
||||
{
|
||||
u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
|
||||
if( addr & 3 )
|
||||
throw R5900Exception::AddressError( addr, false );
|
||||
|
||||
u32 temp = memRead32(addr);
|
||||
|
||||
addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
|
||||
u32 temp;
|
||||
const u32 rt=_Rt_;
|
||||
memRead32(addr, &temp);
|
||||
if(rt!=0)
|
||||
{
|
||||
cpuRegs.GPR.r[rt].UD[0]=temp;
|
||||
}
|
||||
if (!_Rt_) return;
|
||||
cpuRegs.GPR.r[_Rt_].UD[0] = temp;
|
||||
}
|
||||
|
||||
static const s32 LWL_MASK[4] = { 0xffffff, 0x0000ffff, 0x000000ff, 0x00000000 };
|
||||
|
@ -320,13 +433,15 @@ static const s32 LWR_MASK[4] = { 0x000000, 0xff000000, 0xffff0000, 0xffffff00 };
|
|||
static const u8 LWL_SHIFT[4] = { 24, 16, 8, 0 };
|
||||
static const u8 LWR_SHIFT[4] = { 0, 8, 16, 24 };
|
||||
|
||||
void LWL() {
|
||||
if (!_Rt_) return;
|
||||
|
||||
void LWL()
|
||||
{
|
||||
s32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
u32 shift = addr & 3;
|
||||
s32 mem; // ensure the compiler does correct sign extension into 64 bits by using s32
|
||||
memRead32(addr & ~3, (u32*)&mem);
|
||||
|
||||
// ensure the compiler does correct sign extension into 64 bits by using s32
|
||||
s32 mem = memRead32(addr & ~3);
|
||||
|
||||
if (!_Rt_) return;
|
||||
|
||||
cpuRegs.GPR.r[_Rt_].SD[0] = (cpuRegs.GPR.r[_Rt_].SL[0] & LWL_MASK[shift]) |
|
||||
(mem << LWL_SHIFT[shift]);
|
||||
|
@ -342,15 +457,14 @@ void LWL() {
|
|||
*/
|
||||
}
|
||||
|
||||
void LWR() {
|
||||
|
||||
if (!_Rt_) return;
|
||||
|
||||
void LWR()
|
||||
{
|
||||
s32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
u32 shift = addr & 3;
|
||||
|
||||
u32 mem;
|
||||
memRead32(addr & ~3, &mem);
|
||||
u32 mem = memRead32(addr & ~3);
|
||||
|
||||
if (!_Rt_) return;
|
||||
|
||||
// Use unsigned math here, and conditionally sign extend below, when needed.
|
||||
mem = (cpuRegs.GPR.r[_Rt_].UL[0] & LWR_MASK[shift]) | (mem >> LWR_SHIFT[shift]);
|
||||
|
@ -377,16 +491,26 @@ void LWR() {
|
|||
*/
|
||||
}
|
||||
|
||||
void LD() {
|
||||
s32 addr;
|
||||
// dummy variable used as a destination address for writes to the zero register, so
|
||||
// that the zero register always stays zero.
|
||||
PCSX2_ALIGNED16( static GPR_reg m_dummy_gpr_zero );
|
||||
|
||||
addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
if (_Rt_) {
|
||||
memRead64(addr, &cpuRegs.GPR.r[_Rt_].UD[0]);
|
||||
} else {
|
||||
u64 dummy;
|
||||
memRead64(addr, &dummy);
|
||||
}
|
||||
// Returns the x86 address of the requested GPR, which is safe for writing. (includes
|
||||
// special handling for returning a dummy var for GPR0(zero), so that it's value is
|
||||
// always preserved)
|
||||
static u64* gpr_GetWritePtr( uint gpr )
|
||||
{
|
||||
return (u64*)(( gpr == 0 ) ? &m_dummy_gpr_zero : &cpuRegs.GPR.r[gpr]);
|
||||
}
|
||||
|
||||
void LD()
|
||||
{
|
||||
s32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
|
||||
if( addr & 7 )
|
||||
throw R5900Exception::AddressError( addr, false );
|
||||
|
||||
memRead64(addr, gpr_GetWritePtr(_Rt_));
|
||||
}
|
||||
|
||||
static const u64 LDL_MASK[8] =
|
||||
|
@ -402,60 +526,65 @@ static const u8 LDR_SHIFT[8] = { 0, 8, 16, 24, 32, 40, 48, 56 };
|
|||
static const u8 LDL_SHIFT[8] = { 56, 48, 40, 32, 24, 16, 8, 0 };
|
||||
|
||||
|
||||
void LDL() {
|
||||
void LDL()
|
||||
{
|
||||
u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
u32 shift = addr & 7;
|
||||
u64 mem;
|
||||
|
||||
if (!_Rt_) return;
|
||||
u64 mem;
|
||||
memRead64(addr & ~7, &mem);
|
||||
|
||||
if( !_Rt_ ) return;
|
||||
cpuRegs.GPR.r[_Rt_].UD[0] = (cpuRegs.GPR.r[_Rt_].UD[0] & LDL_MASK[shift]) |
|
||||
(mem << LDL_SHIFT[shift]);
|
||||
}
|
||||
|
||||
void LDR() {
|
||||
void LDR()
|
||||
{
|
||||
u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
u32 shift = addr & 7;
|
||||
|
||||
u64 mem;
|
||||
memRead64(addr & ~7, &mem);
|
||||
|
||||
if (!_Rt_) return;
|
||||
memRead64(addr & ~7, &mem);
|
||||
cpuRegs.GPR.r[_Rt_].UD[0] = (cpuRegs.GPR.r[_Rt_].UD[0] & LDR_MASK[shift]) |
|
||||
(mem >> LDR_SHIFT[shift]);
|
||||
}
|
||||
|
||||
void LQ() {
|
||||
u32 addr;
|
||||
void LQ()
|
||||
{
|
||||
u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
|
||||
addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
addr&=~0xf;
|
||||
if( addr & 15 )
|
||||
throw R5900Exception::AddressError( addr, false );
|
||||
|
||||
if (_Rt_) {
|
||||
memRead128(addr, &cpuRegs.GPR.r[_Rt_].UD[0]);
|
||||
} else {
|
||||
u64 val[2];
|
||||
memRead128(addr, val);
|
||||
}
|
||||
memRead128(addr & ~0xf, gpr_GetWritePtr(_Rt_));
|
||||
}
|
||||
|
||||
void SB() {
|
||||
u32 addr;
|
||||
|
||||
addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
memWrite8(addr, cpuRegs.GPR.r[_Rt_].UC[0]);
|
||||
void SB()
|
||||
{
|
||||
u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
memWrite8(addr, cpuRegs.GPR.r[_Rt_].UC[0]);
|
||||
}
|
||||
|
||||
void SH() {
|
||||
u32 addr;
|
||||
void SH()
|
||||
{
|
||||
u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
|
||||
if( addr & 1 )
|
||||
throw R5900Exception::AddressError( addr, true );
|
||||
|
||||
addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
memWrite16(addr, cpuRegs.GPR.r[_Rt_].US[0]);
|
||||
}
|
||||
|
||||
void SW(){
|
||||
u32 addr;
|
||||
void SW()
|
||||
{
|
||||
u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
|
||||
if( addr & 3 )
|
||||
throw R5900Exception::AddressError( addr, true );
|
||||
|
||||
addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
memWrite32(addr, cpuRegs.GPR.r[_Rt_].UL[0]);
|
||||
}
|
||||
|
||||
|
@ -465,17 +594,17 @@ static const u32 SWR_MASK[4] = { 0x00000000, 0x000000ff, 0x0000ffff, 0x00ffffff
|
|||
static const u8 SWR_SHIFT[4] = { 0, 8, 16, 24 };
|
||||
static const u8 SWL_SHIFT[4] = { 24, 16, 8, 0 };
|
||||
|
||||
void SWL() {
|
||||
void SWL()
|
||||
{
|
||||
u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
u32 shift = addr & 3;
|
||||
u32 mem;
|
||||
|
||||
memRead32(addr & ~3, &mem);
|
||||
u32 mem = memRead32( addr & ~3 );
|
||||
|
||||
memWrite32( addr & ~3,
|
||||
(cpuRegs.GPR.r[_Rt_].UL[0] >> SWL_SHIFT[shift]) |
|
||||
(mem & SWL_MASK[shift])
|
||||
);
|
||||
|
||||
/*
|
||||
Mem = 1234. Reg = abcd
|
||||
|
||||
|
@ -489,9 +618,7 @@ void SWL() {
|
|||
void SWR() {
|
||||
u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
u32 shift = addr & 3;
|
||||
u32 mem;
|
||||
|
||||
memRead32(addr & ~3, &mem);
|
||||
u32 mem = memRead32(addr & ~3);
|
||||
|
||||
memWrite32( addr & ~3,
|
||||
(cpuRegs.GPR.r[_Rt_].UL[0] << SWR_SHIFT[shift]) |
|
||||
|
@ -508,10 +635,13 @@ void SWR() {
|
|||
*/
|
||||
}
|
||||
|
||||
void SD() {
|
||||
u32 addr;
|
||||
void SD()
|
||||
{
|
||||
u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
|
||||
if( addr & 7 )
|
||||
throw R5900Exception::AddressError( addr, true );
|
||||
|
||||
addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
memWrite64(addr,&cpuRegs.GPR.r[_Rt_].UD[0]);
|
||||
}
|
||||
|
||||
|
@ -527,7 +657,8 @@ static const u64 SDR_MASK[8] =
|
|||
static const u8 SDL_SHIFT[8] = { 56, 48, 40, 32, 24, 16, 8, 0 };
|
||||
static const u8 SDR_SHIFT[8] = { 0, 8, 16, 24, 32, 40, 48, 56 };
|
||||
|
||||
void SDL() {
|
||||
void SDL()
|
||||
{
|
||||
u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
u32 shift = addr & 7;
|
||||
u64 mem;
|
||||
|
@ -539,7 +670,8 @@ void SDL() {
|
|||
}
|
||||
|
||||
|
||||
void SDR() {
|
||||
void SDR()
|
||||
{
|
||||
u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
u32 shift = addr & 7;
|
||||
u64 mem;
|
||||
|
@ -550,12 +682,14 @@ void SDR() {
|
|||
memWrite64(addr & ~7, &mem );
|
||||
}
|
||||
|
||||
void SQ() {
|
||||
u32 addr;
|
||||
void SQ()
|
||||
{
|
||||
u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
|
||||
if( addr & 15 )
|
||||
throw R5900Exception::AddressError( addr, true );
|
||||
|
||||
addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
|
||||
addr&=~0xf;
|
||||
memWrite128(addr, &cpuRegs.GPR.r[_Rt_].UD[0]);
|
||||
memWrite128(addr & ~0xf, &cpuRegs.GPR.r[_Rt_].UD[0]);
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
|
@ -681,7 +815,7 @@ void SYSCALL()
|
|||
if (call == 0x7c)
|
||||
{
|
||||
if(cpuRegs.GPR.n.a0.UL[0] == 0x10)
|
||||
Console::Write( Color_Cyan, (char*)PSM(PSMu32(cpuRegs.GPR.n.a1.UL[0])) );
|
||||
Console::Write( Color_Cyan, (char*)PSM(memRead32(cpuRegs.GPR.n.a1.UL[0])) );
|
||||
else
|
||||
__Deci2Call( cpuRegs.GPR.n.a0.UL[0], (u32*)PSM(cpuRegs.GPR.n.a1.UL[0]) );
|
||||
}
|
||||
|
@ -727,110 +861,45 @@ void MTSA( void ) {
|
|||
cpuRegs.sa = (s32)cpuRegs.GPR.r[_Rs_].SD[0];
|
||||
}
|
||||
|
||||
// SNY supports three basic modes, two which synchronize memory accesses (related
|
||||
// to the cache) and one which synchronizes the instruction pipeline (effectively
|
||||
// a stall in either case). Our emulation model does not track EE-side pipeline
|
||||
// status or stalls, nor does it implement the CACHE. Thus SYNC need do nothing.
|
||||
void SYNC( void )
|
||||
{
|
||||
}
|
||||
|
||||
// Used to prefetch data into the EE's cache, or schedule a dirty write-back.
|
||||
// CACHE is not emulated at this time (nor is there any need to emulate it), so
|
||||
// this function does nothing in the context of our emulator.
|
||||
void PREF( void )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*********************************************************
|
||||
* Register trap *
|
||||
* Format: OP rs, rt *
|
||||
*********************************************************/
|
||||
|
||||
void TGE() {
|
||||
if (cpuRegs.GPR.r[_Rs_].SD[0]>= cpuRegs.GPR.r[_Rt_].SD[0]) {
|
||||
cpuException(EXC_CODE_Tr, cpuRegs.branch);
|
||||
}
|
||||
//SysPrintf( "TrapInstruction: TGE\n" );
|
||||
}
|
||||
|
||||
void TGEU() {
|
||||
if (cpuRegs.GPR.r[_Rs_].UD[0]>= cpuRegs.GPR.r[_Rt_].UD[0]) {
|
||||
cpuException(EXC_CODE_Tr, cpuRegs.branch);
|
||||
}
|
||||
//SysPrintf( "TrapInstruction: TGEU\n" );
|
||||
}
|
||||
|
||||
void TLT() {
|
||||
if (cpuRegs.GPR.r[_Rs_].SD[0] < cpuRegs.GPR.r[_Rt_].SD[0]) {
|
||||
cpuException(EXC_CODE_Tr, cpuRegs.branch);
|
||||
}
|
||||
//SysPrintf( "TrapInstruction: TLT\n" );
|
||||
}
|
||||
|
||||
void TLTU() {
|
||||
if (cpuRegs.GPR.r[_Rs_].UD[0] < cpuRegs.GPR.r[_Rt_].UD[0]) {
|
||||
cpuException(EXC_CODE_Tr, cpuRegs.branch);
|
||||
}
|
||||
//SysPrintf( "TrapInstruction: TLTU\n" );
|
||||
}
|
||||
|
||||
void TEQ() {
|
||||
if (cpuRegs.GPR.r[_Rs_].SD[0] == cpuRegs.GPR.r[_Rt_].SD[0]) {
|
||||
cpuException(EXC_CODE_Tr, cpuRegs.branch);
|
||||
}
|
||||
//SysPrintf( "TrapInstruction: TEQ\n" );
|
||||
}
|
||||
|
||||
void TNE() {
|
||||
if (cpuRegs.GPR.r[_Rs_].SD[0] != cpuRegs.GPR.r[_Rt_].SD[0]) {
|
||||
cpuException(EXC_CODE_Tr, cpuRegs.branch);
|
||||
}
|
||||
//SysPrintf( "TrapInstruction: TNE\n" );
|
||||
}
|
||||
void TGE() { if (cpuRegs.GPR.r[_Rs_].SD[0] >= cpuRegs.GPR.r[_Rt_].SD[0]) throw R5900Exception::Trap(_TrapCode_); }
|
||||
void TGEU() { if (cpuRegs.GPR.r[_Rs_].UD[0] >= cpuRegs.GPR.r[_Rt_].UD[0]) throw R5900Exception::Trap(_TrapCode_); }
|
||||
void TLT() { if (cpuRegs.GPR.r[_Rs_].SD[0] < cpuRegs.GPR.r[_Rt_].SD[0]) throw R5900Exception::Trap(_TrapCode_); }
|
||||
void TLTU() { if (cpuRegs.GPR.r[_Rs_].UD[0] < cpuRegs.GPR.r[_Rt_].UD[0]) throw R5900Exception::Trap(_TrapCode_); }
|
||||
void TEQ() { if (cpuRegs.GPR.r[_Rs_].SD[0] == cpuRegs.GPR.r[_Rt_].SD[0]) throw R5900Exception::Trap(_TrapCode_); }
|
||||
void TNE() { if (cpuRegs.GPR.r[_Rs_].SD[0] != cpuRegs.GPR.r[_Rt_].SD[0]) throw R5900Exception::Trap(_TrapCode_); }
|
||||
|
||||
/*********************************************************
|
||||
* Trap with immediate operand *
|
||||
* Format: OP rs, rt *
|
||||
*********************************************************/
|
||||
|
||||
void TGEI() {
|
||||
|
||||
if (cpuRegs.GPR.r[_Rs_].SD[0] >= _Imm_) {
|
||||
cpuException(EXC_CODE_Tr, cpuRegs.branch);
|
||||
}
|
||||
//SysPrintf( "TrapInstruction: Immediate\n" );
|
||||
}
|
||||
|
||||
void TGEIU() {
|
||||
if (cpuRegs.GPR.r[_Rs_].UD[0] >= _ImmU_) {
|
||||
cpuException(EXC_CODE_Tr, cpuRegs.branch);
|
||||
}
|
||||
//SysPrintf( "TrapInstruction: Immediate\n" );
|
||||
}
|
||||
|
||||
void TLTI() {
|
||||
if(cpuRegs.GPR.r[_Rs_].SD[0] < _Imm_) {
|
||||
cpuException(EXC_CODE_Tr, cpuRegs.branch);
|
||||
}
|
||||
//SysPrintf( "TrapInstruction: Immediate\n" );
|
||||
}
|
||||
|
||||
void TLTIU() {
|
||||
if (cpuRegs.GPR.r[_Rs_].UD[0] < _ImmU_) {
|
||||
cpuException(EXC_CODE_Tr, cpuRegs.branch);
|
||||
}
|
||||
//SysPrintf( "TrapInstruction: Immediate\n" );
|
||||
}
|
||||
|
||||
void TEQI() {
|
||||
if (cpuRegs.GPR.r[_Rs_].SD[0] == _Imm_) {
|
||||
cpuException(EXC_CODE_Tr, cpuRegs.branch);
|
||||
}
|
||||
//SysPrintf( "TrapInstruction: Immediate\n" );
|
||||
}
|
||||
|
||||
void TNEI() {
|
||||
if (cpuRegs.GPR.r[_Rs_].SD[0] != _Imm_) {
|
||||
cpuException(EXC_CODE_Tr, cpuRegs.branch);
|
||||
}
|
||||
//SysPrintf( "TrapInstruction: Immediate\n" );
|
||||
}
|
||||
void TGEI() { if (cpuRegs.GPR.r[_Rs_].SD[0] >= _Imm_) throw R5900Exception::Trap(); }
|
||||
void TLTI() { if (cpuRegs.GPR.r[_Rs_].SD[0] < _Imm_) throw R5900Exception::Trap(); }
|
||||
void TEQI() { if (cpuRegs.GPR.r[_Rs_].SD[0] == _Imm_) throw R5900Exception::Trap(); }
|
||||
void TNEI() { if (cpuRegs.GPR.r[_Rs_].SD[0] != _Imm_) throw R5900Exception::Trap(); }
|
||||
void TGEIU() { if (cpuRegs.GPR.r[_Rs_].UD[0] >= (u64)_Imm_) throw R5900Exception::Trap(); }
|
||||
void TLTIU() { if (cpuRegs.GPR.r[_Rs_].UD[0] < (u64)_Imm_) throw R5900Exception::Trap(); }
|
||||
|
||||
/*********************************************************
|
||||
* Sa intructions *
|
||||
|
|
|
@ -18,8 +18,10 @@
|
|||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "Sif.h"
|
||||
#include "IopHw.h"
|
||||
#define _PC_ // disables MIPS opcode macros.
|
||||
|
||||
#include "PsxCommon.h"
|
||||
#include "Common.h"
|
||||
#include "Sifcmd.h"
|
||||
|
||||
using namespace std;
|
||||
|
@ -28,8 +30,6 @@ using namespace std;
|
|||
#define sif1dma ((DMACh*)&PS2MEM_HW[0xc400])
|
||||
#define sif2dma ((DMACh*)&PS2MEM_HW[0xc800])
|
||||
|
||||
int eeSifTransfer;
|
||||
|
||||
DMACh *sif0ch;
|
||||
DMACh *sif1ch;
|
||||
DMACh *sif2ch;
|
||||
|
|
|
@ -19,8 +19,6 @@
|
|||
#ifndef __SIF_H__
|
||||
#define __SIF_H__
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
struct sifData{
|
||||
int data,
|
||||
words,
|
||||
|
@ -28,8 +26,6 @@ struct sifData{
|
|||
addr;
|
||||
};
|
||||
|
||||
extern int eeSifTransfer;
|
||||
|
||||
extern DMACh *sif0ch;
|
||||
extern DMACh *sif1ch;
|
||||
extern DMACh *sif2ch;
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
#include "vtlb.h"
|
||||
#include "COP0.h"
|
||||
|
||||
#include "R5900Exceptions.h"
|
||||
|
||||
using namespace R5900;
|
||||
using namespace vtlb_private;
|
||||
|
||||
|
@ -166,7 +168,7 @@ __forceinline void __fastcall MemOp_w0(u32 addr, DataType data)
|
|||
//has to: translate, find function, call function
|
||||
u32 hand=(u8)vmv;
|
||||
u32 paddr=ppf-hand+0x80000000;
|
||||
//SysPrintf("Translted 0x%08X to 0x%08X\n",addr,paddr);
|
||||
//SysPrintf("Translated 0x%08X to 0x%08X\n",addr,paddr);
|
||||
|
||||
switch( DataSize )
|
||||
{
|
||||
|
@ -195,7 +197,7 @@ __forceinline void __fastcall MemOp_w1(u32 addr,const DataType* data)
|
|||
//has to: translate, find function, call function
|
||||
u32 hand=(u8)vmv;
|
||||
u32 paddr=ppf-hand+0x80000000;
|
||||
//SysPrintf("Translted 0x%08X to 0x%08X\n",addr,paddr);
|
||||
//SysPrintf("Translated 0x%08X to 0x%08X\n",addr,paddr);
|
||||
switch( DataSize )
|
||||
{
|
||||
case 64: return ((vtlbMemW64FP*)RWFT[3][1][hand])(paddr, data);
|
||||
|
@ -206,6 +208,7 @@ __forceinline void __fastcall MemOp_w1(u32 addr,const DataType* data)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
mem8_t __fastcall vtlb_memRead8(u32 mem)
|
||||
{
|
||||
return MemOp_r0<8,mem8_t>(mem);
|
||||
|
@ -247,12 +250,6 @@ void __fastcall vtlb_memWrite128(u32 mem, const mem128_t *value)
|
|||
MemOp_w1<128,mem128_t>(mem,value);
|
||||
}
|
||||
|
||||
// Some functions used by interpreters and stuff...
|
||||
// These maintain a "consistent" API with 64/128 reads.
|
||||
void __fastcall memRead8(u32 mem, u8 *out) { *out = vtlb_memRead8( mem ); }
|
||||
void __fastcall memRead16(u32 mem, u16 *out) { *out = vtlb_memRead16( mem ); }
|
||||
void __fastcall memRead32(u32 mem, u32 *out) { *out = vtlb_memRead32( mem ); }
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Error / TLB Miss Handlers
|
||||
//
|
||||
|
@ -265,21 +262,18 @@ static const char* _getModeStr( u32 mode )
|
|||
// Generates a tlbMiss Exception
|
||||
static __forceinline void vtlb_Miss(u32 addr,u32 mode)
|
||||
{
|
||||
Console::Error( "vtlb miss : addr 0x%X, mode %d [%s]", params addr, mode, _getModeStr(mode) );
|
||||
verify(false);
|
||||
|
||||
if (mode==0)
|
||||
cpuTlbMissR(addr, cpuRegs.branch);
|
||||
else
|
||||
cpuTlbMissW(addr, cpuRegs.branch);
|
||||
//Console::Error( "vtlb miss : addr 0x%X, mode %d [%s]", params addr, mode, _getModeStr(mode) );
|
||||
//verify(false);
|
||||
throw R5900Exception::TLBMiss( addr, !!mode );
|
||||
}
|
||||
|
||||
// Just dies a horrible death for now.
|
||||
// Eventually should generate a BusError exception.
|
||||
static __forceinline void vtlb_BusError(u32 addr,u32 mode)
|
||||
{
|
||||
Console::Error( "vtlb bus error : addr 0x%X, mode %d\n", params addr, _getModeStr(mode) );
|
||||
verify(false);
|
||||
//Console::Error( "vtlb bus error : addr 0x%X, mode %d\n", params addr, _getModeStr(mode) );
|
||||
//verify(false);
|
||||
throw R5900Exception::BusError( addr, !!mode );
|
||||
}
|
||||
|
||||
///// Virtual Mapping Errors (TLB Miss)
|
||||
|
@ -344,7 +338,6 @@ void __fastcall vtlbDefaultPhyWrite128(u32 addr,const mem128_t* data) { Console:
|
|||
// VTLB Public API -- Init/Term/RegisterHandler stuff
|
||||
//
|
||||
|
||||
|
||||
// Registers a handler into the VTLB's internal handler array. The handler defines specific behavior
|
||||
// for how memory pages bound to the handler are read from / written to. If any of the handler pointers
|
||||
// are NULL, the memory operations will be mapped to the BusError handler (thus generating BusError
|
||||
|
@ -443,10 +436,9 @@ void vtlb_Mirror(u32 new_region,u32 start,u32 size)
|
|||
__forceinline void* vtlb_GetPhyPtr(u32 paddr)
|
||||
{
|
||||
if (paddr>=VTLB_PMAP_SZ || pmap[paddr>>VTLB_PAGE_BITS]<0)
|
||||
return 0;
|
||||
return NULL;
|
||||
else
|
||||
return reinterpret_cast<void*>(pmap[paddr>>VTLB_PAGE_BITS]+(paddr&VTLB_PAGE_MASK));
|
||||
|
||||
}
|
||||
|
||||
//virtual mappings
|
||||
|
|
|
@ -33,7 +33,7 @@ unsigned char Debug_Read8(unsigned long addr)//just for anycase..
|
|||
{
|
||||
#endif
|
||||
u8 val8;
|
||||
memRead8(addr, &val8);
|
||||
val8 = memRead8(addr);
|
||||
return val8;
|
||||
#ifdef _WIN32
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ BOOL APIENTRY DumpMemProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|||
else
|
||||
{
|
||||
for (addr = start_pc; addr < end_pc; addr ++) {
|
||||
memRead8( addr, &data );
|
||||
data = memRead8( addr );
|
||||
fwrite(&data, 1, 1, fp);
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ void RefreshDebugAll()//refresh disasm and register window
|
|||
|
||||
void MakeDebugOpcode(void)
|
||||
{
|
||||
memRead32( opcode_addr, &cpuRegs.code );
|
||||
cpuRegs.code = memRead32( opcode_addr );
|
||||
}
|
||||
|
||||
void MakeIOPDebugOpcode(void)
|
||||
|
@ -459,7 +459,7 @@ BOOL APIENTRY DebuggerProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam
|
|||
*/
|
||||
EnterRunningState(hDlg);
|
||||
|
||||
memRead32(cpuRegs.pc, &cpuRegs.code);
|
||||
cpuRegs.code = memRead32(cpuRegs.pc);
|
||||
|
||||
{
|
||||
u32 target_pc = 0;
|
||||
|
|
|
@ -204,16 +204,17 @@ DWORD WINAPI Run2(LPVOID lpParam){
|
|||
|
||||
while (1){
|
||||
if (runStatus==RUN){
|
||||
if (PSMu32(cpuRegs.pc)==0x0000000D){
|
||||
const u32 opcode = memRead32(cpuRegs.pc);
|
||||
if (opcode==0x0000000D){
|
||||
sendBREAK('E', 0, runCode, 0x22, runCount);
|
||||
InterlockedExchange(&runStatus, STOP);
|
||||
continue;
|
||||
}
|
||||
if ((runCode==2) && (//next
|
||||
((PSMu32(cpuRegs.pc) & 0xFC000000)==0x0C000000) ||//JAL
|
||||
((PSMu32(cpuRegs.pc) & 0xFC00003F)==0x00000009) ||//JALR
|
||||
((PSMu32(cpuRegs.pc) & 0xFC00003F)==0x0000000C) //SYSCALL
|
||||
)){u32 tmppc=cpuRegs.pc, skip=(PSMu32(cpuRegs.pc) & 0xFC00003F)==0x0000000C ? 4 : 8;
|
||||
((opcode & 0xFC000000)==0x0C000000) ||//JAL
|
||||
((opcode & 0xFC00003F)==0x00000009) ||//JALR
|
||||
((opcode & 0xFC00003F)==0x0000000C) //SYSCALL
|
||||
)){u32 tmppc=cpuRegs.pc, skip=(opcode & 0xFC00003F)==0x0000000C ? 4 : 8;
|
||||
while (cpuRegs.pc!=tmppc+skip)
|
||||
Cpu->Step();
|
||||
}else
|
||||
|
|
|
@ -1839,6 +1839,10 @@
|
|||
RelativePath="..\..\R5900.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\R5900Exceptions.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\R5900OpcodeImpl.cpp"
|
||||
>
|
||||
|
|
|
@ -775,30 +775,6 @@ LRESULT WINAPI MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
MemcardConfig::OpenDialog();
|
||||
break;
|
||||
|
||||
case ID_PROCESSLOW:
|
||||
Config.ThPriority = THREAD_PRIORITY_LOWEST;
|
||||
SaveConfig();
|
||||
CheckMenuItem(gApp.hMenu,ID_PROCESSLOW,MF_CHECKED);
|
||||
CheckMenuItem(gApp.hMenu,ID_PROCESSNORMAL,MF_UNCHECKED);
|
||||
CheckMenuItem(gApp.hMenu,ID_PROCESSHIGH,MF_UNCHECKED);
|
||||
break;
|
||||
|
||||
case ID_PROCESSNORMAL:
|
||||
Config.ThPriority = THREAD_PRIORITY_NORMAL;
|
||||
SaveConfig();
|
||||
CheckMenuItem(gApp.hMenu,ID_PROCESSNORMAL,MF_CHECKED);
|
||||
CheckMenuItem(gApp.hMenu,ID_PROCESSLOW,MF_UNCHECKED);
|
||||
CheckMenuItem(gApp.hMenu,ID_PROCESSHIGH,MF_UNCHECKED);
|
||||
break;
|
||||
|
||||
case ID_PROCESSHIGH:
|
||||
Config.ThPriority = THREAD_PRIORITY_HIGHEST;
|
||||
SaveConfig();
|
||||
CheckMenuItem(gApp.hMenu,ID_PROCESSHIGH,MF_CHECKED);
|
||||
CheckMenuItem(gApp.hMenu,ID_PROCESSNORMAL,MF_UNCHECKED);
|
||||
CheckMenuItem(gApp.hMenu,ID_PROCESSLOW,MF_UNCHECKED);
|
||||
break;
|
||||
|
||||
case ID_CONSOLE:
|
||||
Config.PsxOut = !Config.PsxOut;
|
||||
if(Config.PsxOut)
|
||||
|
@ -919,36 +895,36 @@ void ResetMenuSlots() {
|
|||
|
||||
|
||||
#define _ADDSUBMENU(menu, menun, string) \
|
||||
submenu[menun] = CreatePopupMenu(); \
|
||||
AppendMenu(menu, MF_STRING | MF_POPUP, (UINT)submenu[menun], string);
|
||||
{ submenu[menun] = CreatePopupMenu(); \
|
||||
AppendMenu(menu, MF_STRING | MF_POPUP, (UINT)submenu[menun], string); }
|
||||
|
||||
#define ADDSUBMENU(menun, string) \
|
||||
_ADDSUBMENU(gApp.hMenu, menun, string);
|
||||
|
||||
#define ADDSUBMENUS(submn, menun, string) \
|
||||
submenu[menun] = CreatePopupMenu(); \
|
||||
InsertMenu(submenu[submn], 0, MF_BYPOSITION | MF_STRING | MF_POPUP, (UINT)submenu[menun], string);
|
||||
{ submenu[menun] = CreatePopupMenu(); \
|
||||
InsertMenu(submenu[submn], 0, MF_BYPOSITION | MF_STRING | MF_POPUP, (UINT)submenu[menun], string); }
|
||||
|
||||
#define ADDMENUITEM(menun, string, id) \
|
||||
item.fType = MFT_STRING; \
|
||||
{ item.fType = MFT_STRING; \
|
||||
item.fMask = MIIM_STATE | MIIM_TYPE | MIIM_ID; \
|
||||
item.fState = MFS_ENABLED; \
|
||||
item.wID = id; \
|
||||
sprintf(buf, string); \
|
||||
InsertMenuItem(submenu[menun], 0, TRUE, &item);
|
||||
InsertMenuItem(submenu[menun], 0, TRUE, &item); }
|
||||
|
||||
#define ADDMENUITEMC(menun, string, id) \
|
||||
item.fType = MFT_STRING; \
|
||||
{ item.fType = MFT_STRING; \
|
||||
item.fMask = MIIM_STATE | MIIM_TYPE | MIIM_ID; \
|
||||
item.fState = MFS_ENABLED | MFS_CHECKED; \
|
||||
item.wID = id; \
|
||||
sprintf(buf, string); \
|
||||
InsertMenuItem(submenu[menun], 0, TRUE, &item);
|
||||
InsertMenuItem(submenu[menun], 0, TRUE, &item); }
|
||||
|
||||
#define ADDSEPARATOR(menun) \
|
||||
item.fMask = MIIM_TYPE; \
|
||||
{ item.fMask = MIIM_TYPE; \
|
||||
item.fType = MFT_SEPARATOR; \
|
||||
InsertMenuItem(submenu[menun], 0, TRUE, &item);
|
||||
InsertMenuItem(submenu[menun], 0, TRUE, &item); }
|
||||
|
||||
void CreateMainMenu() {
|
||||
MENUITEMINFO item;
|
||||
|
@ -989,9 +965,6 @@ void CreateMainMenu() {
|
|||
ADDSUBMENU(0, _("&Run"));
|
||||
|
||||
ADDSUBMENUS(0, 1, _("&Process Priority"));
|
||||
ADDMENUITEM(1, _("&Low"), ID_PROCESSLOW );
|
||||
ADDMENUITEM(1, _("High"), ID_PROCESSHIGH);
|
||||
ADDMENUITEM(1, _("Normal"), ID_PROCESSNORMAL);
|
||||
if( IsDevBuild ) {
|
||||
ADDMENUITEM(0,_("&Arguments"), ID_RUN_CMDLINE);
|
||||
}
|
||||
|
@ -1110,9 +1083,6 @@ void CreateMainWindow()
|
|||
CreateMainMenu();
|
||||
|
||||
SetMenu(gApp.hWnd, gApp.hMenu);
|
||||
if(Config.ThPriority==THREAD_PRIORITY_NORMAL) CheckMenuItem(gApp.hMenu,ID_PROCESSNORMAL,MF_CHECKED);
|
||||
if(Config.ThPriority==THREAD_PRIORITY_HIGHEST) CheckMenuItem(gApp.hMenu,ID_PROCESSHIGH,MF_CHECKED);
|
||||
if(Config.ThPriority==THREAD_PRIORITY_LOWEST) CheckMenuItem(gApp.hMenu,ID_PROCESSLOW,MF_CHECKED);
|
||||
if(Config.PsxOut) CheckMenuItem(gApp.hMenu,ID_CONSOLE,MF_CHECKED);
|
||||
if(Config.Patch) CheckMenuItem(gApp.hMenu,ID_PATCHES,MF_CHECKED);
|
||||
if(Config.Profiler) CheckMenuItem(gApp.hMenu,ID_PROFILER,MF_CHECKED);
|
||||
|
|
|
@ -228,6 +228,9 @@ static void TryRecoverFromGsState()
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#include "R5900Exceptions.h"
|
||||
|
||||
void ExecuteCpu()
|
||||
{
|
||||
// Make sure any left-over recovery states are cleaned up.
|
||||
|
@ -259,20 +262,34 @@ void ExecuteCpu()
|
|||
|
||||
timeBeginPeriod( 1 );
|
||||
|
||||
if( CHECK_EEREC )
|
||||
try
|
||||
{
|
||||
while( !g_ReturnToGui )
|
||||
if( CHECK_EEREC )
|
||||
{
|
||||
recExecute();
|
||||
SysUpdate();
|
||||
while( !g_ReturnToGui )
|
||||
{
|
||||
recExecute();
|
||||
SysUpdate();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while( !g_ReturnToGui )
|
||||
{
|
||||
Cpu->Execute();
|
||||
SysUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
catch( R5900Exception::BaseExcept& ex )
|
||||
{
|
||||
while( !g_ReturnToGui )
|
||||
Console::Error( ex.cMessage() );
|
||||
Console::Error( fmt_string( "(EE) PC: 0x%8.8x \tCycle:0x8.8x", ex.cpuState.pc, ex.cpuState.cycle ).c_str() );
|
||||
|
||||
if( !Config.PsxOut )
|
||||
{
|
||||
Cpu->Execute();
|
||||
SysUpdate();
|
||||
// TODO : no console opened, so use a popup to msg the user.
|
||||
// Need to take care to shut down the GS first, or else it'll cause ugliness on fullscreen execution.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -286,8 +303,6 @@ void ExecuteCpu()
|
|||
// Used by Run::FromCD and such
|
||||
void RunExecute( const char* elf_file, bool use_bios )
|
||||
{
|
||||
SetThreadPriority(GetCurrentThread(), Config.ThPriority);
|
||||
SetPriorityClass(GetCurrentProcess(), Config.ThPriority == THREAD_PRIORITY_HIGHEST ? ABOVE_NORMAL_PRIORITY_CLASS : NORMAL_PRIORITY_CLASS);
|
||||
nDisableSC = 1;
|
||||
|
||||
try
|
||||
|
|
|
@ -196,8 +196,6 @@ void IniFile::DoConfig( PcsxConfig& Conf )
|
|||
Entry( "Profiler", Conf.Profiler, false );
|
||||
Entry( "CdvdVerbose", Conf.cdvdPrint, false );
|
||||
|
||||
Entry( "ThreadPriority", Conf.ThPriority, THREAD_PRIORITY_NORMAL );
|
||||
|
||||
SetCurrentSection( "Framelimiter" );
|
||||
Entry( "CustomFps", Conf.CustomFps );
|
||||
Entry( "FrameskipMode", Conf.CustomFrameSkip );
|
||||
|
|
|
@ -707,9 +707,6 @@
|
|||
#define IDC_PATCHNAMELIST 40050
|
||||
#define IDC_GAMENAMESEARCH 40051
|
||||
#define IDC_SEARCHPATCHTEXT 40052
|
||||
#define ID_PROCESSLOW 40053
|
||||
#define ID_PROCESSNORMAL 40054
|
||||
#define ID_PROCESSHIGH 40055
|
||||
#define ID_CONSOLE 40056
|
||||
#define ID_PATCHES 40057
|
||||
#define ID_CONFIG_ADVANCED 40058
|
||||
|
|
|
@ -971,7 +971,7 @@ void psxSetBranchImm( u32 imm )
|
|||
|
||||
//fixme : this is all a huge hack, we base the counter advancements on the average an opcode should take (wtf?)
|
||||
// If that wasn't bad enough we have default values like 9/8 which will get cast to int later
|
||||
// (yeah, that means all sync code couldn't have worked to beginn with)
|
||||
// (yeah, that means all sync code couldn't have worked to begin with)
|
||||
// So for now these are new settings that work.
|
||||
// (rama)
|
||||
|
||||
|
@ -998,7 +998,7 @@ static void iPsxBranchTest(u32 newpc, u32 cpuBranch)
|
|||
// Continue onward with branching here:
|
||||
x86SetJ8( j8Ptr[2] );
|
||||
|
||||
// check if should branch
|
||||
// check if an event is pending
|
||||
SUB32MtoR(ECX, (uptr)&g_psxNextBranchCycle);
|
||||
j8Ptr[0] = JS8( 0 );
|
||||
|
||||
|
@ -1128,10 +1128,7 @@ void psxRecompileNextInstruction(int delayslot)
|
|||
MOV32ItoR(EAX, psxpc);
|
||||
#endif
|
||||
|
||||
s_pCode = iopVirtMemR<int>( psxpc );
|
||||
assert(s_pCode);
|
||||
|
||||
psxRegs.code = *(int *)s_pCode;
|
||||
psxRegs.code = iopMemRead32( psxpc );
|
||||
s_psxBlockCycles++;
|
||||
psxpc += 4;
|
||||
|
||||
|
@ -1146,10 +1143,6 @@ void psxRecompileNextInstruction(int delayslot)
|
|||
|
||||
g_pCurInstInfo++;
|
||||
|
||||
#ifdef PCSX2_VM_COISSUE
|
||||
assert( g_pCurInstInfo->info & EEINSTINFO_COREC );
|
||||
#endif
|
||||
|
||||
g_iopCyclePenalty = 0;
|
||||
rpsxBSC[ psxRegs.code >> 26 ]();
|
||||
s_psxBlockCycles += g_iopCyclePenalty;
|
||||
|
|
|
@ -510,15 +510,12 @@ u32 SuperVUGetVIAddr(int reg, int read)
|
|||
void SuperVUDumpBlock(list<VuBaseBlock*>& blocks, int vuindex)
|
||||
{
|
||||
FILE *f;
|
||||
string filename;
|
||||
char str[256];
|
||||
u32 *mem;
|
||||
u32 i;
|
||||
|
||||
Path::CreateDirectory( "dumps" );
|
||||
ssprintf( filename, "svu%cdump%.4X.txt", s_vu?'0':'1', s_pFnHeader->startpc );
|
||||
filename = Path::Combine( "dumps", filename );
|
||||
|
||||
string filename( Path::Combine( "dumps", fmt_string( "svu%cdump%.4X.txt", s_vu?'0':'1', s_pFnHeader->startpc ) ) );
|
||||
//SysPrintf( "dump1 %x => %s\n", s_pFnHeader->startpc, filename );
|
||||
|
||||
f = fopen( filename.c_str(), "w" );
|
||||
|
|
|
@ -153,7 +153,7 @@ static void iDumpBlock( int startpc, u8 * ptr )
|
|||
if( disR5900GetSym(startpc) != NULL )
|
||||
fprintf(f, "%s\n", disR5900GetSym(startpc));
|
||||
for ( i = startpc; i < s_nEndBlock; i += 4 ) {
|
||||
disR5900Fasm( output, PSMu32( i ), i );
|
||||
disR5900Fasm( output, memRead32( i ), i );
|
||||
fprintf( f, output.c_str() );
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue