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:
Jake.Stine 2009-03-01 21:49:17 +00:00
parent b0c3151aca
commit f270064b41
33 changed files with 689 additions and 555 deletions

View File

@ -19,6 +19,7 @@
#include "PrecompiledHeader.h"
#include "PsxCommon.h"
#include "Common.h"
//THIS ALL IS FOR THE CDROM REGISTERS HANDLING

View File

@ -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"

View File

@ -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.
@ -79,6 +80,23 @@ namespace Exception
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:

View File

@ -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);
}
} } }

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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();

View File

@ -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);

View File

@ -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]);
}
}

View File

@ -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

View File

@ -154,7 +154,6 @@ public:
int Cdda;
int Mdec;
int Patch;
int ThPriority;
int CustomFps;
int Hacks;
int GameFixes;

View File

@ -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;
}

View File

@ -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"

View File

@ -21,6 +21,8 @@
#include "PsxCommon.h"
#include "Misc.h"
#include "R5900.h"
using namespace R3000A;
R3000Acpu *psxCpu;

View File

@ -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.

View File

@ -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
@ -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

177
pcsx2/R5900Exceptions.h Normal file
View File

@ -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

View File

@ -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_;
addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
if( addr & 3 )
throw R5900Exception::AddressError( addr, false );
u32 temp;
const u32 rt=_Rt_;
memRead32(addr, &temp);
if(rt!=0)
{
cpuRegs.GPR.r[rt].UD[0]=temp;
}
u32 temp = memRead32(addr);
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_;
addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_;
addr&=~0xf;
memWrite128(addr, &cpuRegs.GPR.r[_Rt_].UD[0]);
if( addr & 15 )
throw R5900Exception::AddressError( addr, true );
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 *

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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);
}

View File

@ -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;

View File

@ -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

View File

@ -1839,6 +1839,10 @@
RelativePath="..\..\R5900.h"
>
</File>
<File
RelativePath="..\..\R5900Exceptions.h"
>
</File>
<File
RelativePath="..\..\R5900OpcodeImpl.cpp"
>

View File

@ -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);

View File

@ -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

View File

@ -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 );

View File

@ -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

View File

@ -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;

View File

@ -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" );

View File

@ -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() );
}