aligned_stack: Finished conversion of all CALLFunc and _callFunctionArg1 functions to aligned-stack safe __fastcall invocations; only IOP's psxExecute and dispatchers remain to be done. (rev is fully functional in this state tho, on win32 at least)

git-svn-id: http://pcsx2.googlecode.com/svn/branches/aligned_stack@2045 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2009-10-20 20:02:07 +00:00
parent e3a5229076
commit 3e1c1f939c
20 changed files with 151 additions and 555 deletions

View File

@ -31,11 +31,6 @@ typedef int x86IntRegType;
#define EBP 5
#define ESP 4
#define X86ARG1 EAX
#define X86ARG2 ECX
#define X86ARG3 EDX
#define X86ARG4 EBX
#define MM0 0
#define MM1 1
#define MM2 2

View File

@ -38,7 +38,7 @@ __releaseinline void UpdateCP0Status() {
cpuTestHwInts();
}
void WriteCP0Status(u32 value) {
void __fastcall WriteCP0Status(u32 value) {
cpuRegs.CP0.n.Status.val = value;
UpdateCP0Status();
}
@ -221,7 +221,7 @@ __forceinline void COP0_UpdatePCCR()
//if( cpuRegs.CP0.n.Status.b.ERL || !cpuRegs.PERF.n.pccr.b.CTE ) return;
// TODO : Implement memory mode checks here (kernel/super/user)
// For now we just assume user mode.
// For now we just assume kernel mode.
if( cpuRegs.PERF.n.pccr.val & 0xf )
{

View File

@ -16,7 +16,7 @@
#ifndef __COP0_H__
#define __COP0_H__
extern void WriteCP0Status(u32 value);
extern void __fastcall WriteCP0Status(u32 value);
extern void UpdateCP0Status();
extern void WriteTLB(int i);
extern void UnmapTLB(int i);

View File

@ -115,7 +115,7 @@ void psxMemShutdown()
psxMemRLUT = NULL;
}
u8 iopMemRead8(u32 mem)
u8 __fastcall iopMemRead8(u32 mem)
{
mem &= 0x1fffffff;
u32 t = mem >> 16;
@ -159,7 +159,7 @@ u8 iopMemRead8(u32 mem)
}
}
u16 iopMemRead16(u32 mem)
u16 __fastcall iopMemRead16(u32 mem)
{
mem &= 0x1fffffff;
u32 t = mem >> 16;
@ -225,7 +225,7 @@ u16 iopMemRead16(u32 mem)
}
}
u32 iopMemRead32(u32 mem)
u32 __fastcall iopMemRead32(u32 mem)
{
mem &= 0x1fffffff;
u32 t = mem >> 16;
@ -294,7 +294,7 @@ u32 iopMemRead32(u32 mem)
}
}
void iopMemWrite8(u32 mem, u8 value)
void __fastcall iopMemWrite8(u32 mem, u8 value)
{
mem &= 0x1fffffff;
u32 t = mem >> 16;
@ -356,7 +356,7 @@ void iopMemWrite8(u32 mem, u8 value)
}
}
void iopMemWrite16(u32 mem, u16 value)
void __fastcall iopMemWrite16(u32 mem, u16 value)
{
mem &= 0x1fffffff;
u32 t = mem >> 16;
@ -440,7 +440,7 @@ void iopMemWrite16(u32 mem, u16 value)
}
}
void iopMemWrite32(u32 mem, u32 value)
void __fastcall iopMemWrite32(u32 mem, u32 value)
{
mem &= 0x1fffffff;
u32 t = mem >> 16;

View File

@ -75,24 +75,24 @@ static __forceinline u8* iopPhysMem( u32 addr )
#define psxHu16(mem) (*(u16*)&psxH[(mem) & 0xffff])
#define psxHu32(mem) (*(u32*)&psxH[(mem) & 0xffff])
void psxMemAlloc();
void psxMemReset();
void psxMemShutdown();
extern void psxMemAlloc();
extern void psxMemReset();
extern void psxMemShutdown();
u8 iopMemRead8 (u32 mem);
u16 iopMemRead16(u32 mem);
u32 iopMemRead32(u32 mem);
void iopMemWrite8 (u32 mem, u8 value);
void iopMemWrite16(u32 mem, u16 value);
void iopMemWrite32(u32 mem, u32 value);
extern u8 __fastcall iopMemRead8 (u32 mem);
extern u16 __fastcall iopMemRead16(u32 mem);
extern u32 __fastcall iopMemRead32(u32 mem);
extern void __fastcall iopMemWrite8 (u32 mem, u8 value);
extern void __fastcall iopMemWrite16(u32 mem, u16 value);
extern void __fastcall iopMemWrite32(u32 mem, u32 value);
// x86reg and mmreg are always x86 regs
void psxRecMemRead8();
void psxRecMemRead16();
void psxRecMemRead32();
void psxRecMemWrite8();
void psxRecMemWrite16();
void psxRecMemWrite32();
extern void psxRecMemRead8();
extern void psxRecMemRead16();
extern void psxRecMemRead32();
extern void psxRecMemWrite8();
extern void psxRecMemWrite16();
extern void psxRecMemWrite32();
namespace IopMemory
{

View File

@ -70,7 +70,8 @@ void psxShutdown() {
//psxCpu->Shutdown();
}
void psxException(u32 code, u32 bd) {
void __fastcall psxException(u32 code, u32 bd)
{
// PSXCPU_LOG("psxException %x: %x, %x", code, psxHu32(0x1070), psxHu32(0x1074));
//Console.WriteLn("!! psxException %x: %x, %x", code, psxHu32(0x1070), psxHu32(0x1074));
// Set the Cause

View File

@ -194,11 +194,11 @@ extern R3000Acpu *psxCpu;
extern R3000Acpu psxInt;
extern R3000Acpu psxRec;
void psxReset();
void psxShutdown();
void psxException(u32 code, u32 step);
extern void psxReset();
extern void psxShutdown();
extern void __fastcall psxException(u32 code, u32 step);
extern void psxBranchTest();
void psxMemReset();
extern void psxMemReset();
// Subsets
extern void (*psxBSC[64])();

View File

@ -50,7 +50,7 @@ void VU0MI_XGKICK() {
void VU0MI_XTOP() {
}
void vu0ExecMicro(u32 addr) {
void __fastcall vu0ExecMicro(u32 addr) {
VUM_LOG("vu0ExecMicro %x", addr);
if(VU0.VI[REG_VPU_STAT].UL & 0x1) {

View File

@ -46,7 +46,7 @@ void vu1ResetRegs()
static int count;
void vu1ExecMicro(u32 addr)
void __fastcall vu1ExecMicro(u32 addr)
{
while(VU0.VI[REG_VPU_STAT].UL & 0x100)
{

View File

@ -119,14 +119,14 @@ extern void (*VU1regs_UPPER_FD_11_TABLE[32])(_VURegsNum *VUregsn);
// VU0
extern void vu0ResetRegs();
extern void vu0ExecMicro(u32 addr);
extern void __fastcall vu0ExecMicro(u32 addr);
extern void vu0Exec(VURegs* VU);
extern void vu0Finish();
extern void recResetVU0( void );
// VU1
extern void vu1ResetRegs();
extern void vu1ExecMicro(u32 addr);
extern void __fastcall vu1ExecMicro(u32 addr);
extern void vu1Exec(VURegs* VU);
void VU0_UPPER_FD_00();

View File

@ -22,7 +22,6 @@ SuperVUExecuteProgram:
add esp, 4
mov dword ptr [s_callstack], eax
call SuperVUGetProgram
mov s_vu1ebp, ebp
mov s_vu1esi, esi
mov s_vuedi, edi
mov s_vuebx, ebx
@ -39,7 +38,6 @@ SuperVUExecuteProgram:
SuperVUEndProgram:
// restore cpu state
ldmxcsr g_sseMXCSR
mov ebp, s_vu1ebp
mov esi, s_vu1esi
mov edi, s_vuedi
mov ebx, s_vuebx

View File

@ -28,6 +28,7 @@
#include "iCOP0.h"
namespace Interp = R5900::Interpreter::OpcodeImpl::COP0;
using namespace x86Emitter;
namespace R5900 {
namespace Dynarec {
@ -163,12 +164,14 @@ void recMFC0( void )
break;
case 1:
CALLFunc( (uptr)COP0_UpdatePCCR );
MOV32MtoR(EAX, (uptr)&cpuRegs.PERF.n.pcr0);
iFlushCall(FLUSH_NODESTROY);
xCALL( COP0_UpdatePCCR );
xMOV(eax, &cpuRegs.PERF.n.pcr0);
break;
case 3:
CALLFunc( (uptr)COP0_UpdatePCCR );
MOV32MtoR(EAX, (uptr)&cpuRegs.PERF.n.pcr1);
iFlushCall(FLUSH_NODESTROY);
xCALL( COP0_UpdatePCCR );
xMOV(eax, &cpuRegs.PERF.n.pcr1);
break;
}
_deleteEEreg(_Rt_, 0);
@ -240,8 +243,8 @@ void recMTC0()
{
case 12:
iFlushCall(FLUSH_NODESTROY);
//_flushCachedRegs(); //NOTE: necessary?
_callFunctionArg1((uptr)WriteCP0Status, MEM_CONSTTAG, g_cpuConstRegs[_Rt_].UL[0]);
xMOV( ecx, g_cpuConstRegs[_Rt_].UL[0] );
xCALL( WriteCP0Status );
break;
case 9:
@ -254,9 +257,10 @@ void recMTC0()
switch(_Imm_ & 0x3F)
{
case 0:
CALLFunc( (uptr)COP0_UpdatePCCR );
MOV32ItoM((uptr)&cpuRegs.PERF.n.pccr, g_cpuConstRegs[_Rt_].UL[0]);
CALLFunc( (uptr)COP0_DiagnosticPCCR );
iFlushCall(FLUSH_NODESTROY);
xCALL( COP0_UpdatePCCR );
xMOV( ptr32[&cpuRegs.PERF.n.pccr], g_cpuConstRegs[_Rt_].UL[0] );
xCALL( COP0_DiagnosticPCCR );
break;
case 1:
@ -288,8 +292,8 @@ void recMTC0()
{
case 12:
iFlushCall(FLUSH_NODESTROY);
//_flushCachedRegs(); //NOTE: necessary?
_callFunctionArg1((uptr)WriteCP0Status, MEM_GPRTAG|_Rt_, 0);
_eeMoveGPRtoR(ECX, _Rt_);
xCALL( WriteCP0Status );
break;
case 9:
@ -302,9 +306,10 @@ void recMTC0()
switch(_Imm_ & 0x3F)
{
case 0:
CALLFunc( (uptr)COP0_UpdatePCCR );
iFlushCall(FLUSH_NODESTROY);
xCALL( COP0_UpdatePCCR );
_eeMoveGPRtoM((uptr)&cpuRegs.PERF.n.pccr, _Rt_);
CALLFunc( (uptr)COP0_DiagnosticPCCR );
xCALL( COP0_DiagnosticPCCR );
break;
case 1:

View File

@ -136,11 +136,13 @@ static void recCTC2(s32 info)
MOV16ItoM((uptr)&VU0.VI[REG_FBRST].UL,g_cpuConstRegs[_Rt_].UL[0]&0x0c0c);
break;
case REG_CMSAR1: // REG_CMSAR1
iFlushCall(FLUSH_NOCONST);// since CALLFunc
iFlushCall(FLUSH_NOCONST);
assert( _checkX86reg(X86TYPE_VI, REG_VPU_STAT, 0) < 0 &&
_checkX86reg(X86TYPE_VI, REG_TPC, 0) < 0 );
// Execute VU1 Micro SubRoutine
_callFunctionArg1((uptr)vu1ExecMicro, MEM_CONSTTAG, g_cpuConstRegs[_Rt_].UL[0]&0xffff);
xMOV( ecx, g_cpuConstRegs[_Rt_].UL[0]&0xffff );
xCALL( vu1ExecMicro );
break;
default:
{
@ -191,10 +193,10 @@ static void recCTC2(s32 info)
AND32ItoR(EAX,0x0C0C);
MOV16RtoM((uptr)&VU0.VI[REG_FBRST].UL,EAX);
break;
case REG_CMSAR1: // REG_CMSAR1
case REG_CMSAR1: // REG_CMSAR1 (Execute VU1micro Subroutine)
iFlushCall(FLUSH_NOCONST);
_eeMoveGPRtoR(EAX, _Rt_);
_callFunctionArg1((uptr)vu1ExecMicro, MEM_X86TAG|EAX, 0); // Execute VU1 Micro SubRoutine
_eeMoveGPRtoR(ECX, _Rt_);
xCALL( vu1ExecMicro );
break;
default:
_eeMoveGPRtoM((uptr)&VU0.VI[_Fs_].UL,_Rt_);

View File

@ -187,8 +187,6 @@ u8 _hasFreeXMMreg();
void _freeXMMregs();
int _getNumXMMwrite();
// uses MEM_MMXTAG/MEM_XMMTAG to differentiate between the regs
void _recPushReg(int mmreg);
void _signExtendSFtoM(u32 mem);
// returns new index of reg, lower 32 bits already in mmx
@ -196,41 +194,8 @@ void _signExtendSFtoM(u32 mem);
// a negative shift is for sign extension
int _signExtendXMMtoM(u32 to, x86SSERegType from, int candestroy); // returns true if reg destroyed
// Defines for passing register info
// only valid during writes. If write128, then upper 64bits are in an mmxreg
// (mmreg&0xf). Constant is used from gprreg ((mmreg>>16)&0x1f)
enum memtag
{
MEM_EECONSTTAG = 0x0100, // argument is a GPR and comes from g_cpuConstRegs
MEM_PSXCONSTTAG = 0x0200,
MEM_MEMORYTAG = 0x0400,
MEM_MMXTAG = 0x0800, // mmreg is mmxreg
MEM_XMMTAG = 0x8000, // mmreg is xmmreg
MEM_X86TAG = 0x4000, // ignored most of the time
MEM_GPRTAG = 0x2000, // argument is a GPR reg
MEM_CONSTTAG = 0x1000 // argument is a const
};
template<memtag tag> static __forceinline bool IS_REG(s32 reg)
{
return ((reg >= 0) && (reg & tag));
}
template<memtag tag> static __forceinline bool IS_REG(u32 reg)
{
return !!(reg & tag);
}
#define IS_EECONSTREG(reg) IS_REG<MEM_EECONSTTAG>(reg)
#define IS_PSXCONSTREG(reg) IS_REG<MEM_PSXCONSTTAG>(reg)
#define IS_MMXREG(reg) IS_REG<MEM_MMXTAG>(reg)
#define IS_XMMREG(reg) IS_REG<MEM_XMMTAG>(reg)
#define IS_X86REG(reg) IS_REG<MEM_X86TAG>(reg)
#define IS_GPRREG(reg) IS_REG<MEM_GPRTAG>(reg)
#define IS_CONSTREG(reg) IS_REG<MEM_CONSTTAG>(reg)
#define IS_MEMORYREG(reg) IS_REG<MEM_MEMORYTAG>(reg)
static const int MEM_MMXTAG = 0x002; // mmreg is mmxreg
static const int MEM_XMMTAG = 0x004; // mmreg is xmmreg
//////////////////////
// Instruction Info //
@ -425,12 +390,6 @@ extern u16 x86FpuState;
//////////////////////////////////////////////////////////////////////////
// Utility Functions -- that should probably be part of the Emitter.
// see MEM_X defines for argX format
extern void _callPushArg(u32 arg, uptr argmem); /// X86ARG is ignored for 32bit recs
extern void _callFunctionArg1(uptr fn, u32 arg1, uptr arg1mem);
extern void _callFunctionArg2(uptr fn, u32 arg1, u32 arg2, uptr arg1mem, uptr arg2mem);
extern void _callFunctionArg3(uptr fn, u32 arg1, u32 arg2, u32 arg3, uptr arg1mem, uptr arg2mem, uptr arg3mem);
// Moves 128 bits of data using EAX/EDX (used by iCOP2 only currently)
extern void _recMove128MtoM(u32 to, u32 from);

View File

@ -350,7 +350,10 @@ void _psxMoveGPRtoRm(x86IntRegType to, int fromgpr)
void _psxFlushCall(int flushtype)
{
_freeX86regs();
// x86-32 ABI : These registers are not preserved across calls:
_freeX86reg( EAX );
_freeX86reg( ECX );
_freeX86reg( EDX );
if( flushtype & FLUSH_CACHED_REGS )
_psxFlushConstRegs();
@ -436,11 +439,6 @@ void psxRecompileCodeConst1(R3000AFNPTR constcode, R3000AFNPTR_INFO noconstcode)
_psxFlushCall(FLUSH_NODESTROY);
CALLFunc((uptr)zeroEx);
}
// Bios Call: Force the IOP to do a Branch Test ASAP.
// Important! This helps prevent game freeze-ups during boot-up and stage loads.
// Note: Fixes to cdvd have removed the need for this code.
//MOV32MtoR( EAX, (uptr)&psxRegs.cycle );
//MOV32RtoM( (uptr)&g_psxNextBranchCycle, EAX );
}
return;
}
@ -846,7 +844,9 @@ void rpsxSYSCALL()
MOV32ItoM((uptr)&psxRegs.pc, psxpc - 4);
_psxFlushCall(FLUSH_NODESTROY);
_callFunctionArg2((uptr)psxException, MEM_CONSTTAG, MEM_CONSTTAG, 0x20, psxbranch==1);
xMOV( ecx, 0x20 ); // exception code
xMOV( edx, psxbranch==1 ); // branch delay slot?
xCALL( psxException );
CMP32ItoM((uptr)&psxRegs.pc, psxpc-4);
j8Ptr[0] = JE8(0);
@ -867,7 +867,9 @@ void rpsxBREAK()
MOV32ItoM((uptr)&psxRegs.pc, psxpc - 4);
_psxFlushCall(FLUSH_NODESTROY);
_callFunctionArg2((uptr)psxBREAK, MEM_CONSTTAG, MEM_CONSTTAG, 0x24, psxbranch==1);
xMOV( ecx, 0x24 ); // exception code
xMOV( edx, psxbranch==1 ); // branch delay slot?
xCALL( psxException );
CMP32ItoM((uptr)&psxRegs.pc, psxpc-4);
j8Ptr[0] = JE8(0);

View File

@ -594,321 +594,23 @@ void rpsxDIVU_(int info) { rpsxDIVsuper(info, 0); }
PSXRECOMPILE_CONSTCODE3_PENALTY(DIVU, 1, psxInstCycles_Div);
//// LoadStores
#ifdef PCSX2_VIRTUAL_MEM
// VM load store functions (fastest)
//#define REC_SLOWREAD
//#define REC_SLOWWRITE
int _psxPrepareReg(int gprreg)
{
return 0;
}
static u32 s_nAddMemOffset = 0;
static __forceinline void SET_HWLOC_R3000A() {
x86SetJ8(j8Ptr[0]);
SHR32ItoR(ECX, 3);
if( s_nAddMemOffset ) ADD32ItoR(ECX, s_nAddMemOffset);
}
int rpsxSetMemLocation(int regs, int mmreg)
{
s_nAddMemOffset = 0;
MOV32MtoR( ECX, (int)&psxRegs.GPR.r[ regs ] );
if ( _Imm_ != 0 ) ADD32ItoR( ECX, _Imm_ );
SHL32ItoR(ECX, 3);
j8Ptr[0] = JS8(0);
SHR32ItoR(ECX, 3);
AND32ItoR(ECX, 0x1fffff); // 2Mb
return 1;
}
void recLoad32(u32 bit, u32 sign)
{
int mmreg = -1;
#ifdef REC_SLOWREAD
_psxFlushConstReg(_Rs_);
#else
if( PSX_IS_CONST1( _Rs_ ) ) {
// do const processing
int ineax = 0;
_psxOnWriteReg(_Rt_);
mmreg = EAX;
switch(bit) {
case 8: ineax = psxRecMemConstRead8(mmreg, g_psxConstRegs[_Rs_]+_Imm_, sign); break;
case 16:
assert( (g_psxConstRegs[_Rs_]+_Imm_) % 2 == 0 );
ineax = psxRecMemConstRead16(mmreg, g_psxConstRegs[_Rs_]+_Imm_, sign);
break;
case 32:
assert( (g_psxConstRegs[_Rs_]+_Imm_) % 4 == 0 );
ineax = psxRecMemConstRead32(mmreg, g_psxConstRegs[_Rs_]+_Imm_);
break;
}
if( _Rt_ ) MOV32RtoM( (int)&psxRegs.GPR.r[ _Rt_ ], EAX );
}
else
#endif
{
int dohw;
int mmregs = _psxPrepareReg(_Rs_);
_psxOnWriteReg(_Rt_);
_psxDeleteReg(_Rt_, 0);
dohw = rpsxSetMemLocation(_Rs_, mmregs);
switch(bit) {
case 8:
if( sign ) MOVSX32Rm8toROffset(EAX, ECX, PS2MEM_PSX_+s_nAddMemOffset);
else MOVZX32Rm8toROffset(EAX, ECX, PS2MEM_PSX_+s_nAddMemOffset);
break;
case 16:
if( sign ) MOVSX32Rm16toROffset(EAX, ECX, PS2MEM_PSX_+s_nAddMemOffset);
else MOVZX32Rm16toROffset(EAX, ECX, PS2MEM_PSX_+s_nAddMemOffset);
break;
case 32:
MOV32RmtoROffset(EAX, ECX, PS2MEM_PSX_+s_nAddMemOffset);
break;
}
if( dohw ) {
j8Ptr[1] = JMP8(0);
SET_HWLOC_R3000A();
switch(bit) {
case 8:
CALLFunc( (int)psxRecMemRead8 );
if( sign ) MOVSX32R8toR(EAX, EAX);
else MOVZX32R8toR(EAX, EAX);
break;
case 16:
CALLFunc( (int)psxRecMemRead16 );
if( sign ) MOVSX32R16toR(EAX, EAX);
else MOVZX32R16toR(EAX, EAX);
break;
case 32:
CALLFunc( (int)psxRecMemRead32 );
break;
}
x86SetJ8(j8Ptr[1]);
}
if( _Rt_ )
MOV32RtoM( (int)&psxRegs.GPR.r[ _Rt_ ], EAX );
}
}
void rpsxLB() { recLoad32(8, 1); }
void rpsxLBU() { recLoad32(8, 0); }
void rpsxLH() { recLoad32(16, 1); }
void rpsxLHU() { recLoad32(16, 0); }
void rpsxLW() { recLoad32(32, 0); }
extern void rpsxMemConstClear(u32 mem);
// check if mem is executable, and clear it
__declspec(naked) void rpsxWriteMemClear()
{
_asm {
mov edx, ecx
shr edx, 14
and dl, 0xfc
add edx, psxRecLUT
test dword ptr [edx], 0xffffffff
jnz Clear32
ret
Clear32:
// recLUT[mem>>16] + (mem&0xfffc)
mov edx, dword ptr [edx]
mov eax, ecx
and eax, 0xfffc
// edx += 2*eax
shl eax, 1
add edx, eax
cmp dword ptr [edx], 0
je ClearRet
sub esp, 4
mov dword ptr [esp], edx
call psxRecClearMem
add esp, 4
ClearRet:
ret
}
}
extern u32 s_psxBlockCycles;
void recStore(int bit)
{
#ifdef REC_SLOWWRITE
_psxFlushConstReg(_Rs_);
#else
if( PSX_IS_CONST1( _Rs_ ) ) {
u8* pjmpok;
u32 addr = g_psxConstRegs[_Rs_]+_Imm_;
int doclear = 0;
if( !(addr & 0x10000000) ) {
// check g_psxWriteOk
CMP32ItoM((uptr)&g_psxWriteOk, 0);
pjmpok = JE8(0);
}
switch(bit) {
case 8:
if( PSX_IS_CONST1(_Rt_) ) doclear = psxRecMemConstWrite8(addr, MEM_PSXCONSTTAG|(_Rt_<<16));
else {
_psxMoveGPRtoR(EAX, _Rt_);
doclear = psxRecMemConstWrite8(addr, EAX);
}
break;
case 16:
assert( (addr)%2 == 0 );
if( PSX_IS_CONST1(_Rt_) ) doclear = psxRecMemConstWrite16(addr, MEM_PSXCONSTTAG|(_Rt_<<16));
else {
_psxMoveGPRtoR(EAX, _Rt_);
doclear = psxRecMemConstWrite16(addr, EAX);
}
break;
case 32:
assert( (addr)%4 == 0 );
if( PSX_IS_CONST1(_Rt_) ) doclear = psxRecMemConstWrite32(addr, MEM_PSXCONSTTAG|(_Rt_<<16));
else {
_psxMoveGPRtoR(EAX, _Rt_);
doclear = psxRecMemConstWrite32(addr, EAX);
}
break;
}
if( !(addr & 0x10000000) ) {
if( doclear ) rpsxMemConstClear((addr)&~3);
x86SetJ8(pjmpok);
}
}
else
#endif
{
int dohw;
int mmregs = _psxPrepareReg(_Rs_);
dohw = rpsxSetMemLocation(_Rs_, mmregs);
CMP32ItoM((uptr)&g_psxWriteOk, 0);
u8* pjmpok = JE8(0);
if( PSX_IS_CONST1( _Rt_ ) ) {
switch(bit) {
case 8: MOV8ItoRmOffset(ECX, g_psxConstRegs[_Rt_], PS2MEM_PSX_+s_nAddMemOffset); break;
case 16: MOV16ItoRmOffset(ECX, g_psxConstRegs[_Rt_], PS2MEM_PSX_+s_nAddMemOffset); break;
case 32: MOV32ItoRmOffset(ECX, g_psxConstRegs[_Rt_], PS2MEM_PSX_+s_nAddMemOffset); break;
}
}
else {
switch(bit) {
case 8:
MOV8MtoR(EAX, (int)&psxRegs.GPR.r[ _Rt_ ]);
MOV8RtoRmOffset(ECX, EAX, PS2MEM_PSX_+s_nAddMemOffset);
break;
case 16:
MOV16MtoR(EAX, (int)&psxRegs.GPR.r[ _Rt_ ]);
MOV16RtoRmOffset(ECX, EAX, PS2MEM_PSX_+s_nAddMemOffset);
break;
case 32:
MOV32MtoR(EAX, (int)&psxRegs.GPR.r[ _Rt_ ]);
MOV32RtoRmOffset(ECX, EAX, PS2MEM_PSX_+s_nAddMemOffset);
break;
}
}
if( s_nAddMemOffset ) ADD32ItoR(ECX, s_nAddMemOffset);
CMP32MtoR(ECX, (uptr)&g_psxMaxRecMem);
j8Ptr[1] = JAE8(0);
if( bit < 32 ) AND8ItoR(ECX, 0xfc);
CALLFunc((u32)rpsxWriteMemClear);
if( dohw ) {
j8Ptr[2] = JMP8(0);
SET_HWLOC_R3000A();
if( PSX_IS_CONST1(_Rt_) ) {
switch(bit) {
case 8: MOV8ItoR(EAX, g_psxConstRegs[_Rt_]); break;
case 16: MOV16ItoR(EAX, g_psxConstRegs[_Rt_]); break;
case 32: MOV32ItoR(EAX, g_psxConstRegs[_Rt_]); break;
}
}
else {
switch(bit) {
case 8: MOV8MtoR(EAX, (int)&psxRegs.GPR.r[ _Rt_ ]); break;
case 16: MOV16MtoR(EAX, (int)&psxRegs.GPR.r[ _Rt_ ]); break;
case 32: MOV32MtoR(EAX, (int)&psxRegs.GPR.r[ _Rt_ ]); break;
}
}
if( s_nAddMemOffset != 0 ) ADD32ItoR(ECX, s_nAddMemOffset);
// some type of hardware write
switch(bit) {
case 8: CALLFunc( (int)psxRecMemWrite8 ); break;
case 16: CALLFunc( (int)psxRecMemWrite16 ); break;
case 32: CALLFunc( (int)psxRecMemWrite32 ); break;
}
x86SetJ8(j8Ptr[2]);
}
x86SetJ8(j8Ptr[1]);
x86SetJ8(pjmpok);
}
}
void rpsxSB() { recStore(8); }
void rpsxSH() { recStore(16); }
void rpsxSW() { recStore(32); }
REC_FUNC(LWL);
REC_FUNC(LWR);
REC_FUNC(SWL);
REC_FUNC(SWR);
#else
// TLB loadstore functions
REC_FUNC(LWL);
REC_FUNC(LWR);
REC_FUNC(SWL);
REC_FUNC(SWR);
using namespace x86Emitter;
static void rpsxLB()
{
_psxDeleteReg(_Rs_, 1);
_psxOnWriteReg(_Rt_);
_psxDeleteReg(_Rt_, 0);
MOV32MtoR(X86ARG1, (uptr)&psxRegs.GPR.r[_Rs_]);
if (_Imm_) ADD32ItoR(X86ARG1, _Imm_);
_callFunctionArg1((uptr)iopMemRead8, X86ARG1|MEM_X86TAG, 0);
MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[_Rs_]);
if (_Imm_) ADD32ItoR(ECX, _Imm_);
xCALL( iopMemRead8 ); // returns value in EAX
if (_Rt_) {
MOVSX32R8toR(EAX, EAX);
MOV32RtoM((uptr)&psxRegs.GPR.r[_Rt_], EAX);
@ -922,9 +624,9 @@ static void rpsxLBU()
_psxOnWriteReg(_Rt_);
_psxDeleteReg(_Rt_, 0);
MOV32MtoR(X86ARG1, (uptr)&psxRegs.GPR.r[_Rs_]);
if (_Imm_) ADD32ItoR(X86ARG1, _Imm_);
_callFunctionArg1((uptr)iopMemRead8, X86ARG1|MEM_X86TAG, 0);
MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[_Rs_]);
if (_Imm_) ADD32ItoR(ECX, _Imm_);
xCALL( iopMemRead8 ); // returns value in EAX
if (_Rt_) {
MOVZX32R8toR(EAX, EAX);
MOV32RtoM((uptr)&psxRegs.GPR.r[_Rt_], EAX);
@ -938,9 +640,9 @@ static void rpsxLH()
_psxOnWriteReg(_Rt_);
_psxDeleteReg(_Rt_, 0);
MOV32MtoR(X86ARG1, (uptr)&psxRegs.GPR.r[_Rs_]);
if (_Imm_) ADD32ItoR(X86ARG1, _Imm_);
_callFunctionArg1((uptr)iopMemRead16, X86ARG1|MEM_X86TAG, 0);
MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[_Rs_]);
if (_Imm_) ADD32ItoR(ECX, _Imm_);
xCALL( iopMemRead16 ); // returns value in EAX
if (_Rt_) {
MOVSX32R16toR(EAX, EAX);
MOV32RtoM((uptr)&psxRegs.GPR.r[_Rt_], EAX);
@ -954,9 +656,9 @@ static void rpsxLHU()
_psxOnWriteReg(_Rt_);
_psxDeleteReg(_Rt_, 0);
MOV32MtoR(X86ARG1, (uptr)&psxRegs.GPR.r[_Rs_]);
if (_Imm_) ADD32ItoR(X86ARG1, _Imm_);
_callFunctionArg1((uptr)iopMemRead16, X86ARG1|MEM_X86TAG, 0);
MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[_Rs_]);
if (_Imm_) ADD32ItoR(ECX, _Imm_);
xCALL( iopMemRead16 ); // returns value in EAX
if (_Rt_) {
MOVZX32R16toR(EAX, EAX);
MOV32RtoM((uptr)&psxRegs.GPR.r[_Rt_], EAX);
@ -971,13 +673,13 @@ static void rpsxLW()
_psxDeleteReg(_Rt_, 0);
_psxFlushCall(FLUSH_EVERYTHING);
MOV32MtoR(X86ARG1, (uptr)&psxRegs.GPR.r[_Rs_]);
if (_Imm_) ADD32ItoR(X86ARG1, _Imm_);
MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[_Rs_]);
if (_Imm_) ADD32ItoR(ECX, _Imm_);
TEST32ItoR(X86ARG1, 0x10000000);
TEST32ItoR(ECX, 0x10000000);
j8Ptr[0] = JZ8(0);
_callFunctionArg1((uptr)iopMemRead32, X86ARG1|MEM_X86TAG, 0);
xCALL( iopMemRead32 ); // returns value in EAX
if (_Rt_) {
MOV32RtoM((uptr)&psxRegs.GPR.r[_Rt_], EAX);
}
@ -985,11 +687,11 @@ static void rpsxLW()
x86SetJ8(j8Ptr[0]);
// read from psM directly
AND32ItoR(X86ARG1, 0x1fffff);
ADD32ItoR(X86ARG1, (uptr)psxM);
AND32ItoR(ECX, 0x1fffff);
ADD32ItoR(ECX, (uptr)psxM);
MOV32RmtoR( X86ARG1, X86ARG1 );
MOV32RtoM( (uptr)&psxRegs.GPR.r[_Rt_], X86ARG1);
MOV32RmtoR( ECX, ECX );
MOV32RtoM( (uptr)&psxRegs.GPR.r[_Rt_], ECX);
x86SetJ8(j8Ptr[1]);
PSX_DEL_CONST(_Rt_);
@ -1000,9 +702,10 @@ static void rpsxSB()
_psxDeleteReg(_Rs_, 1);
_psxDeleteReg(_Rt_, 1);
MOV32MtoR(X86ARG1, (uptr)&psxRegs.GPR.r[_Rs_]);
if (_Imm_) ADD32ItoR(X86ARG1, _Imm_);
_callFunctionArg2((uptr)iopMemWrite8, X86ARG1|MEM_X86TAG, MEM_MEMORYTAG, 0, (uptr)&psxRegs.GPR.r[_Rt_]);
MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[_Rs_]);
if (_Imm_) ADD32ItoR(ECX, _Imm_);
xMOV( edx, &psxRegs.GPR.r[_Rt_] );
xCALL( iopMemWrite8 );
}
static void rpsxSH()
@ -1010,9 +713,10 @@ static void rpsxSH()
_psxDeleteReg(_Rs_, 1);
_psxDeleteReg(_Rt_, 1);
MOV32MtoR(X86ARG1, (uptr)&psxRegs.GPR.r[_Rs_]);
if (_Imm_) ADD32ItoR(X86ARG1, _Imm_);
_callFunctionArg2((uptr)iopMemWrite16, X86ARG1|MEM_X86TAG, MEM_MEMORYTAG, 0, (uptr)&psxRegs.GPR.r[_Rt_]);
MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[_Rs_]);
if (_Imm_) ADD32ItoR(ECX, _Imm_);
xMOV( edx, &psxRegs.GPR.r[_Rt_] );
xCALL( iopMemWrite16 );
}
static void rpsxSW()
@ -1020,13 +724,12 @@ static void rpsxSW()
_psxDeleteReg(_Rs_, 1);
_psxDeleteReg(_Rt_, 1);
MOV32MtoR(X86ARG1, (uptr)&psxRegs.GPR.r[_Rs_]);
if (_Imm_) ADD32ItoR(X86ARG1, _Imm_);
_callFunctionArg2((uptr)iopMemWrite32, X86ARG1|MEM_X86TAG, MEM_MEMORYTAG, 0, (uptr)&psxRegs.GPR.r[_Rt_]);
MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[_Rs_]);
if (_Imm_) ADD32ItoR(ECX, _Imm_);
xMOV( edx, &psxRegs.GPR.r[_Rt_] );
xCALL( iopMemWrite32 );
}
#endif // end load store
//// SLL
void rpsxSLL_const()
{

View File

@ -236,7 +236,8 @@ void _flushConstRegs()
int _allocX86reg(int x86reg, int type, int reg, int mode)
{
int i;
assert( reg >= 0 && reg < 32 );
pxAssertDev( reg >= 0 && reg < 32, "Register index out of bounds." );
pxAssertDev( x86reg != ESP && x86reg != EBP, "Allocation of ESP/EBP is not allowed!" );
// don't alloc EAX and ESP,EBP if MODE_NOFRAME
int oldmode = mode;
@ -448,14 +449,10 @@ void _freeX86reg(int x86reg)
x86regs[x86reg].inuse = 0;
}
void _freeX86regs() {
int i;
for (i=0; i<iREGCNT_GPR; i++) {
if (!x86regs[i].inuse) continue;
void _freeX86regs()
{
for (int i=0; i<iREGCNT_GPR; i++)
_freeX86reg(i);
}
}
// MMX Caching
@ -863,88 +860,6 @@ void SetFPUstate() {
}
}
__forceinline void _callPushArg(u32 arg, uptr argmem)
{
if( IS_X86REG(arg) ) {
PUSH32R(arg&0xff);
}
else if( IS_CONSTREG(arg) ) {
PUSH32I(argmem);
}
else if( IS_GPRREG(arg) ) {
SUB32ItoR(ESP, 4);
_eeMoveGPRtoRm(ESP, arg&0xff);
}
else if( IS_XMMREG(arg) ) {
SUB32ItoR(ESP, 4);
SSEX_MOVD_XMM_to_Rm(ESP, arg&0xf);
}
else if( IS_MMXREG(arg) ) {
SUB32ItoR(ESP, 4);
MOVD32MMXtoRm(ESP, arg&0xf);
}
else if( IS_EECONSTREG(arg) ) {
PUSH32I(g_cpuConstRegs[(arg>>16)&0x1f].UL[0]);
}
else if( IS_PSXCONSTREG(arg) ) {
PUSH32I(g_psxConstRegs[(arg>>16)&0x1f]);
}
else if( IS_MEMORYREG(arg) ) {
PUSH32M(argmem);
}
else {
assert( (arg&0xfff0) == 0 );
// assume it is a GPR reg
PUSH32R(arg&0xf);
}
}
__forceinline void _callFunctionArg1(uptr fn, u32 arg1, uptr arg1mem)
{
_callPushArg(arg1, arg1mem);
CALLFunc((uptr)fn);
ADD32ItoR(ESP, 4);
}
__forceinline void _callFunctionArg2(uptr fn, u32 arg1, u32 arg2, uptr arg1mem, uptr arg2mem)
{
_callPushArg(arg2, arg2mem);
_callPushArg(arg1, arg1mem);
CALLFunc((uptr)fn);
ADD32ItoR(ESP, 8);
}
__forceinline void _callFunctionArg3(uptr fn, u32 arg1, u32 arg2, u32 arg3, uptr arg1mem, uptr arg2mem, uptr arg3mem)
{
_callPushArg(arg3, arg3mem);
_callPushArg(arg2, arg2mem);
_callPushArg(arg1, arg1mem);
CALLFunc((uptr)fn);
ADD32ItoR(ESP, 12);
}
void _recPushReg(int mmreg)
{
if( IS_XMMREG(mmreg) ) {
SUB32ItoR(ESP, 4);
SSEX_MOVD_XMM_to_Rm(ESP, mmreg&0xf);
}
else if( IS_MMXREG(mmreg) ) {
SUB32ItoR(ESP, 4);
MOVD32MMXtoRm(ESP, mmreg&0xf);
}
else if( IS_EECONSTREG(mmreg) ) {
PUSH32I(g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0]);
}
else if( IS_PSXCONSTREG(mmreg) ) {
PUSH32I(g_psxConstRegs[(mmreg>>16)&0x1f]);
}
else {
assert( (mmreg&0xfff0) == 0 );
PUSH32R(mmreg);
}
}
void _signExtendSFtoM(u32 mem)
{
LAHF();

View File

@ -371,7 +371,7 @@ static void _DynGen_StackFrameCheck()
xCMP( esp, &s_store_esp );
xForwardJE8 skipassert_esp;
xXOR( ecx, ecx ); // 0 specifies ESI
xXOR( ecx, ecx ); // 0 specifies ESP
xMOV( edx, esp );
xCALL( StackFrameCheckFailed );
xMOV( esp, &s_store_esp ); // half-hearted frame recovery attempt!
@ -867,6 +867,12 @@ void CheckForBIOSEnd()
{
xMOV( eax, &cpuRegs.pc );
/*xCMP( eax, 0x00200008 );
xJE(ExitRec);
xCMP( eax, 0x00100008 );
xJE(ExitRec);*/
xCMP( eax, 0x00200008 );
xForwardJE8 CallExitRec;
@ -975,7 +981,10 @@ void LoadBranchState()
void iFlushCall(int flushtype)
{
_freeX86regs();
// Free registers that are not saved across function calls (x86-32 ABI):
_freeX86reg(EAX);
_freeX86reg(ECX);
_freeX86reg(EDX);
if( flushtype & FLUSH_FREE_XMM )
_freeXMMregs();
@ -1076,6 +1085,8 @@ static u32 eeScaleBlockCycles()
// setting "branch = 2";
static void iBranchTest(u32 newpc)
{
_DynGen_StackFrameCheck();
if( g_ExecBiosHack ) CheckForBIOSEnd();
// Check the Event scheduler if our "cycle target" has been reached.
@ -1306,7 +1317,7 @@ void __fastcall dyna_block_discard(u32 start,u32 sz)
// EBP/stackframe before issuing a RET, else esp/ebp will be incorrect.
#ifdef _MSC_VER
__asm leave; __asm jmp [ExitRecompiledCode]
__asm leave __asm jmp [ExitRecompiledCode]
#else
__asm__ __volatile__( "leave\n jmp *%[exitRec]\n" : : [exitRec] "m" (ExitRecompiledCode) : );
#endif
@ -1321,7 +1332,7 @@ void __fastcall dyna_page_reset(u32 start,u32 sz)
mmap_MarkCountedRamPage( start );
#ifdef _MSC_VER
__asm leave; __asm jmp [ExitRecompiledCode]
__asm leave __asm jmp [ExitRecompiledCode]
#else
__asm__ __volatile__( "leave\n jmp *%[exitRec]\n" : : [exitRec] "m" (ExitRecompiledCode) : );
#endif

View File

@ -19,6 +19,8 @@
#include "iR5900.h"
#include "R5900OpcodeTables.h"
using namespace x86Emitter;
extern void _vu0WaitMicro();
extern void _vu0FinishMicro();
@ -311,14 +313,12 @@ static void recCTC2() {
}
else MOV32ItoM((uptr)&microVU0.regs->VI[_Rd_].UL, 0);
break;
case REG_CMSAR1:
case REG_CMSAR1: // Execute VU1 Micro SubRoutine
if (_Rt_) {
MOV32MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[0]);
PUSH32R(EAX);
MOV32MtoR(ECX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[0]);
}
else PUSH32I(0);
CALLFunc((uptr)vu1ExecMicro); // Execute VU1 Micro SubRoutine
ADD32ItoR(ESP, 4);
else XOR32RtoR(ECX,ECX);
xCALL(vu1ExecMicro);
break;
case REG_FBRST:
if (!_Rt_) {

View File

@ -43,6 +43,7 @@
#include "AppConfig.h"
using namespace std;
using namespace x86Emitter;
// temporary externs
extern void iDumpVU0Registers();
@ -2526,8 +2527,8 @@ static void SuperVUAssignRegs()
int s_writeQ, s_writeP;
// declare the saved registers
uptr s_vu1esp, s_callstack;//, s_vu1esp
uptr s_vu1ebp, s_vuebx, s_vuedi, s_vu1esi;
uptr s_vu1esp, s_callstack;
uptr s_vuebx, s_vuedi, s_vu1esi;
static int s_recWriteQ, s_recWriteP; // wait times during recompilation
static int s_needFlush; // first bit - Q, second bit - P, third bit - Q has been written, fourth bit - P has been written
@ -2576,6 +2577,11 @@ void SuperVUCleanupProgram(u32 startpc, int vuindex)
// entry point of all vu programs from emulator calls
__declspec(naked) void SuperVUExecuteProgram(u32 startpc, int vuindex)
{
// Stackframe setup for the recompiler:
// We rewind the stack 4 bytes, which places the parameters of this function before
// any calls we might make from recompiled code. The return address for this function
// call is subsequently stored in s_callstack.
__asm
{
mov eax, dword ptr [esp]
@ -2585,20 +2591,15 @@ __declspec(naked) void SuperVUExecuteProgram(u32 startpc, int vuindex)
call SuperVUGetProgram
// save cpu state
mov s_vu1ebp, ebp
mov s_vu1esi, esi // have to save even in Release
mov s_vuedi, edi // have to save even in Release
//mov s_vu1ebp, ebp
mov s_vu1esi, esi
mov s_vuedi, edi
mov s_vuebx, ebx
}
#ifdef PCSX2_DEBUG
__asm
{
mov s_vu1esp, esp
}
#endif
__asm
{
//stmxcsr s_ssecsr
ldmxcsr g_sseVUMXCSR
@ -2618,7 +2619,7 @@ __declspec(naked) static void SuperVUEndProgram()
// restore cpu state
ldmxcsr g_sseMXCSR
mov ebp, s_vu1ebp
//mov ebp, s_vu1ebp
mov esi, s_vu1esi
mov edi, s_vuedi
mov ebx, s_vuebx
@ -3105,6 +3106,8 @@ void VuBaseBlock::Recompile()
_x86regs* endx86 = &s_vecRegArray[nEndx86];
for (int i = 0; i < iREGCNT_GPR; ++i)
{
if( i == ESP || i == EBP ) continue;
if (endx86[i].inuse)
{
@ -3652,7 +3655,8 @@ void VuInstruction::Recompile(list<VuInstruction>::iterator& itinst, u32 vuxyz)
TEST32ItoM((uptr)&VU0.VI[REG_FBRST].UL, s_vu ? 0x400 : 0x004);
u8* ptr = JZ8(0);
OR32ItoM((uptr)&VU0.VI[REG_VPU_STAT].UL, s_vu ? 0x200 : 0x002);
_callFunctionArg1((uptr)hwIntcIrq, MEM_CONSTTAG, s_vu ? INTC_VU1 : INTC_VU0);
xMOV( ecx, s_vu ? INTC_VU1 : INTC_VU0 );
xCALL( hwIntcIrq );
x86SetJ8(ptr);
}
if (ptr[1] & 0x08000000) // T flag
@ -3660,7 +3664,8 @@ void VuInstruction::Recompile(list<VuInstruction>::iterator& itinst, u32 vuxyz)
TEST32ItoM((uptr)&VU0.VI[REG_FBRST].UL, s_vu ? 0x800 : 0x008);
u8* ptr = JZ8(0);
OR32ItoM((uptr)&VU0.VI[REG_VPU_STAT].UL, s_vu ? 0x400 : 0x004);
_callFunctionArg1((uptr)hwIntcIrq, MEM_CONSTTAG, s_vu ? INTC_VU1 : INTC_VU0);
xMOV( ecx, s_vu ? INTC_VU1 : INTC_VU0 );
xCALL( hwIntcIrq );
x86SetJ8(ptr);
}
@ -4379,7 +4384,7 @@ void recVUMI_XGKICK(VURegs *VU, int info)
recVUMI_XGKICK_(VU);
}
int isreg = _allocX86reg(X86ARG2, X86TYPE_VI | (s_vu ? X86TYPE_VU1 : 0), _Is_, MODE_READ);
int isreg = _allocX86reg(ECX, X86TYPE_VI | (s_vu ? X86TYPE_VU1 : 0), _Is_, MODE_READ);
_freeX86reg(isreg); // flush
x86regs[isreg].inuse = 1;
x86regs[isreg].type = X86TYPE_VITEMP;