General emulator memory work, regarding my new policy that most (or all) cpu and hardware registers should be standard globals, as it makes our lives a lot easier in general (and their memory footprint is small so it won't adversely affect the virtual memory availability of the host operating systems). Details:

* Removed the hacky g_pVU1 pointer, which required VU1 cpu registers to be part of VU0.  Replaced it with a standard VU1 variable (mimics all other CPU registers, which are standard static vars).  We were using translation functions/tables for all VU0 memory operations anyway, so this was a no-brainer.
 * Removed code from microVU that was only there to help deal with the fact that g_pVU1 was annoying.
 * Turned eeMem->HW into a static global array eeHw [64k].

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@3692 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2010-08-27 03:21:16 +00:00
parent 28dc7cfe69
commit bda94b16cd
40 changed files with 546 additions and 480 deletions

View File

@ -588,8 +588,8 @@ struct INTCregisters
u32 _padding2[3];
};
#define dmacRegs ((DMACregisters*)(eeMem->HW+0xE000))
#define intcRegs ((INTCregisters*)(eeMem->HW+0xF000))
#define dmacRegs ((DMACregisters*)(eeHw+0xE000))
#define intcRegs ((INTCregisters*)(eeHw+0xF000))
static __fi void throwBusError(const char *s)
{

View File

@ -129,7 +129,7 @@ void iDumpRegisters(u32 startpc, u32 temp)
__Log("gif: %x %x %x", psHu32(0x3000), psHu32(0x3010), psHu32(0x3020));
for(i = 0; i < ArraySize(dmacs); ++i) {
DMACh* p = (DMACh*)(&eeMem->HW[dmacs[i]]);
DMACh* p = (DMACh*)(&eeHw[dmacs[i]]);
__Log("dma%d c%x m%x q%x t%x s%x", i, p->chcr._u32, p->madr, p->qwc, p->tadr, p->sadr);
}
__Log(L"dmac " + dmacRegs->ctrl.desc() + L" " + dmacRegs->stat.desc() + L" " + dmacRegs->rbsr.desc() + L" " + dmacRegs->rbor.desc());

View File

@ -277,7 +277,7 @@ struct GIFregisters
u32 padding9[3];
};
#define gifRegs ((GIFregisters*)(eeMem->HW+0x3000))
#define gifRegs ((GIFregisters*)(eeHw+0x3000))
extern tGSTransferStatus GSTransferStatus;

View File

@ -54,8 +54,8 @@ void hwReset()
{
hwInit();
memzero_ptr<Ps2MemSize::Hardware>( eeMem->HW );
//memset(eeMem->HW+0x2000, 0, 0x0000e000);
memzero_ptr<Ps2MemSize::Hardware>( eeHw );
//memset(eeHw+0x2000, 0, 0x0000e000);
psHu32(SBUS_F260) = 0x1D000060;

View File

@ -20,11 +20,11 @@
//////////////////////////////////////////////////////////////////////////
// Hardware FIFOs (128 bit access only!)
//
// VIF0 -- 0x10004000 -- eeMem->HW[0x4000]
// VIF1 -- 0x10005000 -- eeMem->HW[0x5000]
// GIF -- 0x10006000 -- eeMem->HW[0x6000]
// IPUout -- 0x10007000 -- eeMem->HW[0x7000]
// IPUin -- 0x10007010 -- eeMem->HW[0x7010]
// VIF0 -- 0x10004000 -- eeHw[0x4000]
// VIF1 -- 0x10005000 -- eeHw[0x5000]
// GIF -- 0x10006000 -- eeHw[0x6000]
// IPUout -- 0x10007000 -- eeHw[0x7000]
// IPUin -- 0x10007010 -- eeHw[0x7010]
void __fastcall ReadFIFO_page_4(u32 mem, mem128_t *out);
void __fastcall ReadFIFO_page_5(u32 mem, mem128_t *out);

View File

@ -270,7 +270,7 @@ mem32_t __fastcall hwRead32_page_00(u32 mem)
case 0x830: return (u16)counters[1].hold;
}
return *((u32*)&eeMem->HW[mem]);
return *((u32*)&eeHw[mem]);
}
// Reads hardware registers for page 1 (counters 2 and 3)
@ -288,7 +288,7 @@ mem32_t __fastcall hwRead32_page_01(u32 mem)
case 0x1820: return (u16)counters[3].target;
}
return *((u32*)&eeMem->HW[mem]);
return *((u32*)&eeHw[mem]);
}
// Reads hardware registers for page 15 (0x0F).
@ -309,7 +309,7 @@ static __fi mem32_t __hwRead32_page_0F( u32 mem, bool intchack )
if( mem == ics ) // INTC_STAT
{
if( intchack ) IntCHackCheck();
return *((u32*)&eeMem->HW[ics]);
return *((u32*)&eeHw[ics]);
}
switch( mem )
@ -355,7 +355,7 @@ static __fi mem32_t __hwRead32_page_0F( u32 mem, bool intchack )
}
return 0;
}
return *((u32*)&eeMem->HW[mem]);
return *((u32*)&eeHw[mem]);
}
mem32_t __fastcall hwRead32_page_0F(u32 mem)
@ -435,7 +435,7 @@ mem32_t __fastcall hwRead32_generic(u32 mem)
jNO_DEFAULT;
}
return *((u32*)&eeMem->HW[masked_mem]);
return *((u32*)&eeHw[masked_mem]);
}
/////////////////////////////////////////////////////////////////////////

View File

@ -750,7 +750,7 @@ void __fastcall hwWrite32_page_00( u32 mem, u32 value )
case 0x830: rcntWhold(1, value); return;
}
*((u32*)&eeMem->HW[mem]) = value;
*((u32*)&eeHw[mem]) = value;
}
// Page 1 of HW memory houses registers for Counters 2 and 3
@ -768,7 +768,7 @@ void __fastcall hwWrite32_page_01( u32 mem, u32 value )
case 0x1820: rcntWtarget(3, value); return;
}
*((u32*)&eeMem->HW[mem]) = value;
*((u32*)&eeHw[mem]) = value;
}
// page 2 is the IPU register space!

View File

@ -245,7 +245,7 @@ struct IPUregisters {
u32 dummy3[2];
};
#define ipuRegs ((IPUregisters*)(&eeMem->HW[0x2000]))
#define ipuRegs ((IPUregisters*)(&eeHw[0x2000]))
struct tIPU_cmd
{

View File

@ -468,7 +468,7 @@ void __fastcall iopMemWrite32(u32 mem, u32 value)
// wtf? why were we writing to the EE's sif space? Commenting this out doesn't
// break any of my games, and should be more correct, but I guess we'll see. --air
//*(u32*)(eeMem->HW+0xf200+(mem&0xf0)) = value;
//*(u32*)(eeHw+0xf200+(mem&0xf0)) = value;
return;
}
else if (t == 0x1000)

View File

@ -602,10 +602,12 @@ protected:
void OnPageFaultEvent( const PageFaultInfo& info, bool& handled );
};
mmap_PageFaultHandler mmap_faultHandler;
static mmap_PageFaultHandler mmap_faultHandler;
EEVM_MemoryAllocMess* eeMem = NULL;
__pagealigned u8 eeHw[Ps2MemSize::Hardware];
void memAlloc()
{
if( eeMem == NULL )

View File

@ -35,32 +35,32 @@ static __fi void ZeroQWC( void* dest )
}
// Various useful locations
#define spr0 ((DMACh*)&eeMem->HW[0xD000])
#define spr1 ((DMACh*)&eeMem->HW[0xD400])
#define spr0 ((DMACh*)&eeHw[0xD000])
#define spr1 ((DMACh*)&eeHw[0xD400])
#define gif ((DMACh*)&eeMem->HW[0xA000])
#define gif ((DMACh*)&eeHw[0xA000])
#define vif0ch ((DMACh*)&eeMem->HW[0x8000])
#define vif1ch ((DMACh*)&eeMem->HW[0x9000])
#define vif0ch ((DMACh*)&eeHw[0x8000])
#define vif1ch ((DMACh*)&eeHw[0x9000])
#define sif0dma ((DMACh*)&eeMem->HW[0xc000])
#define sif1dma ((DMACh*)&eeMem->HW[0xc400])
#define sif2dma ((DMACh*)&eeMem->HW[0xc800])
#define sif0dma ((DMACh*)&eeHw[0xc000])
#define sif1dma ((DMACh*)&eeHw[0xc400])
#define sif2dma ((DMACh*)&eeHw[0xc800])
#define ipu0dma ((DMACh *)&eeMem->HW[0xb000])
#define ipu1dma ((DMACh *)&eeMem->HW[0xb400])
#define ipu0dma ((DMACh *)&eeHw[0xb000])
#define ipu1dma ((DMACh *)&eeHw[0xb400])
#define PSM(mem) (vtlb_GetPhyPtr((mem)&0x1fffffff)) //pcsx2 is a competition.The one with most hacks wins :D
#define psHs8(mem) (*(s8 *)&eeMem->HW[(mem) & 0xffff])
#define psHs16(mem) (*(s16*)&eeMem->HW[(mem) & 0xffff])
#define psHs32(mem) (*(s32*)&eeMem->HW[(mem) & 0xffff])
#define psHs64(mem) (*(s64*)&eeMem->HW[(mem) & 0xffff])
#define psHu8(mem) (*(u8 *)&eeMem->HW[(mem) & 0xffff])
#define psHu16(mem) (*(u16*)&eeMem->HW[(mem) & 0xffff])
#define psHu32(mem) (*(u32*)&eeMem->HW[(mem) & 0xffff])
#define psHu64(mem) (*(u64*)&eeMem->HW[(mem) & 0xffff])
#define psHu128(mem)(*(u128*)&eeMem->HW[(mem) & 0xffff])
#define psHs8(mem) (*(s8 *)&eeHw[(mem) & 0xffff])
#define psHs16(mem) (*(s16*)&eeHw[(mem) & 0xffff])
#define psHs32(mem) (*(s32*)&eeHw[(mem) & 0xffff])
#define psHs64(mem) (*(s64*)&eeHw[(mem) & 0xffff])
#define psHu8(mem) (*(u8 *)&eeHw[(mem) & 0xffff])
#define psHu16(mem) (*(u16*)&eeHw[(mem) & 0xffff])
#define psHu32(mem) (*(u32*)&eeHw[(mem) & 0xffff])
#define psHu64(mem) (*(u64*)&eeHw[(mem) & 0xffff])
#define psHu128(mem)(*(u128*)&eeHw[(mem) & 0xffff])
#define psMs8(mem) (*(s8 *)&eeMem->Main[(mem) & 0x1ffffff])
#define psMs16(mem) (*(s16*)&eeMem->Main[(mem) & 0x1ffffff])
@ -114,7 +114,7 @@ static __fi void ZeroQWC( void* dest )
#define psSu64(mem) (*(u64 *)&eeMem->Scratch[(mem) & 0x3fff])
#define psSu128(mem) (*(u128*)&eeMem->Scratch[(mem) & 0x3fff])
#define psH_DMACh(mem) (*(DMACh*)&eeMem->HW[(mem) & 0xffff])
#define psH_DMACh(mem) (*(DMACh*)&eeHw[(mem) & 0xffff])
extern void memAlloc();
extern void memReset(); // clears PS2 ram and loads the bios. Throws Exception::FileNotFound on error.

View File

@ -37,15 +37,55 @@ typedef u32 mem32_t;
typedef u64 mem64_t;
typedef u128 mem128_t;
// --------------------------------------------------------------------------------------
// Future-Planned VTLB pagefault scheme!
// --------------------------------------------------------------------------------------
// When enabled, the VTLB will use a large-area reserved memory range of 512megs for EE
// physical ram/rom access. The base ram will be committed at 0x00000000, and ROMs will be
// at 0x1fc00000, etc. All memory ranges in between will be uncommitted memory -- which
// means that the memory will *not* count against the operating system's physical memory
// pool.
//
// When the VTLB generates memory operations (loads/stores), it will assume that the op
// is addressing either RAM or ROM, and by assuming that it can generate a completely efficient
// direct memory access (one AND and one MOV instruction). If the access is to another area of
// memory, such as hardware registers or scratchpad, the access will generate a page fault, the
// compiled block will be cleared and re-compiled using "full" VTLB translation logic.
//
#define VTLB_UsePageFaulting 0
#if VTLB_UsePageFaulting
// The order of the components in this struct *matter* -- it has been laid out so that the
// full breadth of PS2 RAM and ROM mappings are directly supported.
struct EEVM_MemoryAllocMess
{
u8 (&Main)[Ps2MemSize::Base]; // Main memory (hard-wired to 32MB)
u8 _padding1[0x1e000000-Ps2MemSize::Base]
u8 (&ROM1)[Ps2MemSize::Rom1]; // DVD player
u8 _padding2[0x1e040000-(0x1e000000+Ps2MemSize::Rom1)]
u8 (&EROM)[Ps2MemSize::ERom]; // DVD player extensions
u8 _padding3[0x1e400000-(0x1e040000+Ps2MemSize::EROM)]
u8 (&ROM2)[Ps2MemSize::Rom2]; // Chinese extensions
u8 _padding4[0x1fc00000-(0x1e040000+Ps2MemSize::Rom2)];
u8 (&ROM)[Ps2MemSize::Rom]; // Boot rom (4MB)
};
#else
struct EEVM_MemoryAllocMess
{
u8 Scratch[Ps2MemSize::Scratch]; // Scratchpad!
u8 Main[Ps2MemSize::Base]; // Main memory (hard-wired to 32MB)
u8 HW[Ps2MemSize::Hardware]; // Hardware registers
u8 ROM[Ps2MemSize::Rom]; // Boot rom (4MB)
u8 ROM1[Ps2MemSize::Rom1]; // DVD player
u8 ROM2[Ps2MemSize::Rom2]; // Chinese extensions (?)
u8 EROM[Ps2MemSize::ERom]; // DVD player extensions (?)
u8 ROM2[Ps2MemSize::Rom2]; // Chinese extensions
u8 EROM[Ps2MemSize::ERom]; // DVD player extensions
// Two 1 megabyte (max DMA) buffers for reading and writing to high memory (>32MB).
// Such accesses are not documented as causing bus errors but as the memory does
@ -56,4 +96,13 @@ struct EEVM_MemoryAllocMess
u8 ZeroWrite[_1mb];
};
#endif
// EE Hardware registers.
// DevNote: These are done as a static array instead of a pointer in order to allow for simpler
// macros and reference handles to be defined (we can safely use compile-time references to
// registers instead of having to use instance variables).
extern __pagealigned u8 eeHw[Ps2MemSize::Hardware];
extern EEVM_MemoryAllocMess* eeMem;

View File

@ -154,7 +154,7 @@ void SaveStateBase::FreezeMainMemory()
// ---------------------------
FreezeMem(eeMem->Main, Ps2MemSize::Base); // 32 MB main memory
FreezeMem(eeMem->Scratch, Ps2MemSize::Scratch); // scratch pad
FreezeMem(eeMem->HW, Ps2MemSize::Hardware); // hardware memory
FreezeMem(eeHw, Ps2MemSize::Hardware); // hardware memory
FreezeMem(psxM, Ps2MemSize::IopRam); // 2 MB main memory
FreezeMem(psxH, Ps2MemSize::IopHardware); // hardware memory

View File

@ -119,40 +119,56 @@ struct ialuPipe {
struct VURegs {
VECTOR VF[32]; // VF and VI need to be first in this struct for proper mapping
REG_VI VI[32]; // needs to be 128bit x 32 (cottonvibes)
VECTOR ACC;
REG_VI q;
REG_VI p;
uint idx; // VU index (0 or 1)
// flags/cycle are needed by VIF dma code, so they have to be here (for now)
// We may replace these by accessors in the future, if merited.
u32 cycle;
u32 flags;
// Current opcode being interpreted or recompiled (this var is used by Interps and superVU
// but not microVU. Would like to have it local to their respective classes... someday)
u32 code;
// branch/branchpc are used by interpreter only, but making them local to the interpreter
// classes requires considerable code refactoring. Maybe later. >_<
u32 branch;
u32 branchpc;
// MAC/Status flags -- these are used by interpreters and superVU, but are kind of hacky
// and shouldn't be relied on for any useful/valid info. Would like to move them out of
// this struct eventually.
u32 macflag;
u32 statusflag;
u32 clipflag;
u32 cycle;
u32 flags;
void (*vuExec)(VURegs*);
VIFregisters *vifRegs;
u8 *Mem;
u8 *Micro;
u32 code;
u32 maxmem;
u32 maxmicro;
u16 branch;
u16 ebit;
u32 branchpc;
u32 ebit;
fmacPipe fmac[8];
fdivPipe fdiv;
efuPipe efu;
ialuPipe ialu[8];
VURegs() :
Mem( NULL )
, Micro( NULL )
VURegs()
{
Mem = NULL;
Micro = NULL;
}
bool IsVU1() const;
bool IsVU0() const;
VIFregisters& GetVifRegs() const
{
return IsVU1() ? vif1RegsRef : vif0RegsRef;
}
};
@ -167,23 +183,15 @@ enum VUPipeState
VUPIPE_XGKICK
};
struct _VURegsNum {
u8 pipe; // if 0xff, COP2
u8 VFwrite;
u8 VFwxyzw;
u8 VFr0xyzw;
u8 VFr1xyzw;
u8 VFread0;
u8 VFread1;
u32 VIwrite;
u32 VIread;
int cycles;
};
extern __aligned16 VURegs vuRegs[2];
extern VURegs* g_pVU1;
extern __aligned16 VURegs VU0;
// Obsolete(?) -- I think I'd rather use vu0Regs/vu1Regs or actually have these explicit to any
// CPP file that needs them only. --air
static VURegs& VU0 = vuRegs[0];
static VURegs& VU1 = vuRegs[1];
#define VU1 (*g_pVU1)
__fi bool VURegs::IsVU1() const { return this == &vuRegs[1]; }
__fi bool VURegs::IsVU0() const { return this == &vuRegs[0]; }
extern u32* GET_VU_MEM(VURegs* VU, u32 addr);

View File

@ -44,8 +44,6 @@
using namespace R5900;
__aligned16 VURegs VU0;
void COP2_BC2() { Int_COP2BC2PrintTable[_Rt_]();}
void COP2_SPECIAL() { Int_COP2SPECIAL1PrintTable[_Funct_]();}

View File

@ -47,15 +47,6 @@ static void _vu0Exec(VURegs* VU)
int vireg;
int discard=0;
if(VU0.VI[REG_TPC].UL >= VU0.maxmicro){
#ifdef CPU_LOG
Console.WriteLn("VU0 memory overflow!!: %x", VU->VI[REG_TPC].UL);
#endif
VU0.VI[REG_VPU_STAT].UL&= ~0x1;
VU->cycle++;
return;
}
ptr = (u32*)&VU->Micro[VU->VI[REG_TPC].UL];
VU->VI[REG_TPC].UL+=8;
@ -171,14 +162,8 @@ static void _vu0Exec(VURegs* VU)
void vu0Exec(VURegs* VU)
{
if (VU->VI[REG_TPC].UL >= VU->maxmicro) {
#ifdef CPU_LOG
Console.Warning("VU0 memory overflow!!: %x", VU->VI[REG_TPC].UL);
#endif
VU0.VI[REG_VPU_STAT].UL&= ~0x1;
} else {
VU0.VI[REG_TPC].UL &= VU0_PROGMASK;
_vu0Exec(VU);
}
VU->cycle++;
if (VU->VI[0].UL != 0) DbgCon.Error("VI[0] != 0!!!!\n");

View File

@ -24,8 +24,6 @@
#include "VUmicro.h"
VURegs* g_pVU1;
#ifdef PCSX2_DEBUG
u32 vudump = 0;
#endif

View File

@ -48,13 +48,6 @@ static void _vu1Exec(VURegs* VU)
int vireg;
int discard=0;
if(VU->VI[REG_TPC].UL >= VU->maxmicro){
CPU_LOG("VU1 memory overflow!!: %x", VU->VI[REG_TPC].UL);
VU->VI[REG_TPC].UL &= 0x3FFF;
/*VU0.VI[REG_VPU_STAT].UL&= ~0x100;
VU->cycle++;
return;*/
}
ptr = (u32*)&VU->Micro[VU->VI[REG_TPC].UL];
VU->VI[REG_TPC].UL+=8;
@ -182,6 +175,7 @@ InterpVU1::InterpVU1()
void InterpVU1::Step()
{
VU1.VI[REG_TPC].UL &= VU1_PROGMASK;
vu1Exec( &VU1 );
}
@ -190,11 +184,11 @@ void InterpVU1::Execute(u32 cycles)
for (int i = (int)cycles; i > 0 ; i--) {
if (!(VU0.VI[REG_VPU_STAT].UL & 0x100)) {
if (VU1.branch || VU1.ebit) {
vu1Exec(&VU1); // run branch delay slot?
Step(); // run branch delay slot?
}
break;
}
vu1Exec(&VU1);
Step();
}
}

View File

@ -18,6 +18,17 @@
#include "VU.h"
#include "VUops.h"
#include "R5900.h"
static const uint VU0_MEMSIZE = 0x1000;
static const uint VU0_PROGSIZE = 0x1000;
static const uint VU1_MEMSIZE = 0x4000;
static const uint VU1_PROGSIZE = 0x4000;
static const uint VU0_MEMMASK = VU0_MEMSIZE-1;
static const uint VU0_PROGMASK = VU0_PROGSIZE-1;
static const uint VU1_MEMMASK = VU1_MEMSIZE-1;
static const uint VU1_PROGMASK = VU1_PROGSIZE-1;
#define vuRunCycles (512*12) // Cycles to run ExecuteBlockJIT() for (called from within recs)
#define vu0RunCycles (512*12) // Cycles to run vu0 for whenever ExecuteBlock() is called
#define vu1RunCycles (3000000) // mVU1 uses this for inf loop detection on dev builds

View File

@ -18,10 +18,12 @@
#include "Common.h"
#include "VUmicro.h"
__aligned16 VURegs vuRegs[2];
static u8* m_vuAllMem = NULL;
static const uint m_vuMemSize =
0x1000 + // VU0micro memory
0x4000+0x800 + // VU0 memory and VU1 registers
0x4000 + // VU0 memory
0x4000 + // VU1 memory
0x4000;
@ -33,12 +35,9 @@ void vuMicroMemAlloc()
if( m_vuAllMem == NULL )
throw Exception::OutOfMemory( L"VU0 and VU1 on-chip memory" );
pxAssume( sizeof( VURegs ) <= 0x800 );
u8* curpos = m_vuAllMem;
VU0.Micro = curpos; curpos += 0x1000;
VU0.Mem = curpos; curpos += 0x4000;
g_pVU1 = (VURegs*)curpos; curpos += 0x800;
VU1.Micro = curpos; curpos += 0x4000;
VU1.Mem = curpos;
//curpos += 0x4000;
@ -50,7 +49,6 @@ void vuMicroMemShutdown()
vtlb_free( m_vuAllMem, m_vuMemSize );
m_vuAllMem = NULL;
g_pVU1 = NULL;
}
void vuMicroMemReset()
@ -72,17 +70,6 @@ void vuMicroMemReset()
memzero_ptr<4*1024>(VU0.Mem);
memzero_ptr<4*1024>(VU0.Micro);
/* this is kinda tricky, maxmem is set to 0x4400 here,
tho it's not 100% accurate, since the mem goes from
0x0000 - 0x1000 (Mem) and 0x4000 - 0x4400 (VU1 Regs),
i guess it shouldn't be a problem,
at least hope so :) (linuz)
*/
VU0.maxmem = 0x4800-4; //We are allocating 0x800 for vu1 reg's
VU0.maxmicro = 0x1000-4;
VU0.vuExec = vu0Exec;
VU0.vifRegs = vif0Regs;
// === VU1 Initialization ===
memzero(VU1.ACC);
memzero(VU1.VF);
@ -94,13 +81,6 @@ void vuMicroMemReset()
VU1.VI[0].UL = 0;
memzero_ptr<16*1024>(VU1.Mem);
memzero_ptr<16*1024>(VU1.Micro);
VU1.maxmem = 0x4000-4;//16*1024-4;
VU1.maxmicro = 0x4000-4;
// VU1.VF = (VECTOR*)(VU0.Mem + 0x4000);
// VU1.VI = (REG_VI*)(VU0.Mem + 0x4200);
VU1.vuExec = vu1Exec;
VU1.vifRegs = vif1Regs;
}
void SaveStateBase::vuMicroFreeze()

View File

@ -15,12 +15,11 @@
#include "PrecompiledHeader.h"
#include "Common.h"
#include <cmath>
#include "VUops.h"
#include "GS.h"
#include <cmath>
//Lower/Upper instructions can use that..
#define _Ft_ ((VU->code >> 16) & 0x1F) // The rt part of the instruction register
#define _Fs_ ((VU->code >> 11) & 0x1F) // The rd part of the instruction register
@ -1579,9 +1578,9 @@ static __fi void _vuMR32(VURegs * VU) {
__fi u32* GET_VU_MEM(VURegs* VU, u32 addr) // non-static, also used by sVU for now.
{
if( VU == g_pVU1 ) return (u32*)(VU1.Mem+(addr&0x3fff));
if( addr >= 0x4000 ) return (u32*)(VU0.Mem+(addr&0x43f0)); // get VF and VI regs (they're mapped to 0x4xx0 in VU0 mem!)
return (u32*)(VU0.Mem+(addr&0x0fff)); // for addr 0x0000 to 0x4000 just wrap around
if( VU == &vuRegs[1] ) return (u32*)(vuRegs[1].Mem+(addr&0x3fff));
if( addr >= 0x4000 ) return (u32*)(vuRegs[0].Mem+(addr&0x43f0)); // get VF and VI regs (they're mapped to 0x4xx0 in VU0 mem!)
return (u32*)(vuRegs[0].Mem+(addr&0x0fff)); // for addr 0x0000 to 0x4000 just wrap around
}
static __ri void _vuLQ(VURegs * VU) {
@ -2015,7 +2014,7 @@ static __ri void _vuEEXP(VURegs * VU) {
static __ri void _vuXITOP(VURegs * VU) {
if (_It_ == 0) return;
VU->VI[_It_].US[0] = VU->vifRegs->itop;
VU->VI[_It_].US[0] = VU->GetVifRegs().itop;
}
static __ri void _vuXGKICK(VURegs * VU)
@ -2032,7 +2031,7 @@ static __ri void _vuXGKICK(VURegs * VU)
static __ri void _vuXTOP(VURegs * VU) {
if(_It_ == 0) return;
VU->VI[_It_].US[0] = (u16)VU->vifRegs->top;
VU->VI[_It_].US[0] = (u16)VU->GetVifRegs().top;
}
#define GET_VF0_FLAG(reg) (((reg)==0)?(1<<REG_VF0_FLAG):0)

View File

@ -27,6 +27,19 @@
#define MAC_Reset( VU ) VU->VI[REG_MAC_FLAG].UL = VU->VI[REG_MAC_FLAG].UL & (~0xFFFF)
struct _VURegsNum {
u8 pipe; // if 0xff, COP2
u8 VFwrite;
u8 VFwxyzw;
u8 VFr0xyzw;
u8 VFr1xyzw;
u8 VFread0;
u8 VFread1;
u32 VIwrite;
u32 VIread;
int cycles;
};
#define __vuRegsCall __fastcall
typedef void __vuRegsCall FnType_VuRegsN(_VURegsNum *VUregsn);
typedef FnType_VuRegsN* Fnptr_VuRegsN;

View File

@ -15,6 +15,7 @@
#pragma once
#include "MemoryTypes.h"
#include "R5900.h"
enum vif0_stat_flags
@ -214,8 +215,8 @@ struct VIFregisters {
extern VIFregisters *vifRegs;
#define vif0RegsRef ((VIFregisters&)eeMem->HW[0x3800])
#define vif1RegsRef ((VIFregisters&)eeMem->HW[0x3c00])
static VIFregisters& vif0RegsRef = (VIFregisters&)eeHw[0x3800];
static VIFregisters& vif1RegsRef = (VIFregisters&)eeHw[0x3C00];
#define vif0Regs (&vif0RegsRef)
#define vif1Regs (&vif1RegsRef)

View File

@ -183,7 +183,7 @@ bool _VIF1chain()
__fi void vif1SetupTransfer()
{
tDMA_TAG *ptag;
DMACh& vif1c = (DMACh&)eeMem->HW[0x9000];
DMACh& vif1c = (DMACh&)eeHw[0x9000];
switch (vif1.dmamode)
{

View File

@ -39,32 +39,33 @@ static __fi void vifFlush(int idx) {
static __fi void vuExecMicro(int idx, u32 addr) {
VURegs* VU = nVif[idx].VU;
VIFregisters& vifRegs = VU->GetVifRegs();
int startcycles = 0;
//vifFlush(idx);
//if(vifX.vifstalled == true) return;
if (VU->vifRegs->itops > (idx ? 0x3ffu : 0xffu)) {
Console.WriteLn("VIF%d ITOP overrun! %x", idx, VU->vifRegs->itops);
VU->vifRegs->itops &= (idx ? 0x3ffu : 0xffu);
if (vifRegs.itops > (idx ? 0x3ffu : 0xffu)) {
Console.WriteLn("VIF%d ITOP overrun! %x", idx, vifRegs.itops);
vifRegs.itops &= (idx ? 0x3ffu : 0xffu);
}
VU->vifRegs->itop = VU->vifRegs->itops;
vifRegs.itop = vifRegs.itops;
if (idx) {
// in case we're handling a VIF1 execMicro, set the top with the tops value
VU->vifRegs->top = VU->vifRegs->tops & 0x3ff;
vifRegs.top = vifRegs.tops & 0x3ff;
// is DBF flag set in VIF_STAT?
if (VU->vifRegs->stat.DBF) {
if (vifRegs.stat.DBF) {
// it is, so set tops with base, and clear the stat DBF flag
VU->vifRegs->tops = VU->vifRegs->base;
VU->vifRegs->stat.DBF = false;
vifRegs.tops = vifRegs.base;
vifRegs.stat.DBF = false;
}
else {
// it is not, so set tops with base + offset, and set stat DBF flag
VU->vifRegs->tops = VU->vifRegs->base + VU->vifRegs->ofst;
VU->vifRegs->stat.DBF = true;
vifRegs.tops = vifRegs.base + vifRegs.ofst;
vifRegs.stat.DBF = true;
}
}

View File

@ -639,6 +639,10 @@
RelativePath="..\..\x86\microVU_IR.h"
>
</File>
<File
RelativePath="..\..\x86\microVU_IR.inl"
>
</File>
<File
RelativePath="..\..\x86\microVU_Log.inl"
>

View File

@ -19,6 +19,22 @@
#include "Common.h"
#include "microVU.h"
// Include all the *.inl files (Needed because C++ sucks with templates and *.cpp files)
#include "microVU_Clamp.inl"
#include "microVU_Misc.inl"
#include "microVU_Log.inl"
#include "microVU_Analyze.inl"
#include "microVU_IR.inl"
#include "microVU_Alloc.inl"
#include "microVU_Upper.inl"
#include "microVU_Lower.inl"
#include "microVU_Tables.inl"
#include "microVU_Flags.inl"
#include "microVU_Branch.inl"
#include "microVU_Compile.inl"
#include "microVU_Execute.inl"
#include "microVU_Macro.inl"
//------------------------------------------------------------------
// Micro VU - Global Variables
//------------------------------------------------------------------
@ -70,107 +86,93 @@ static __fi void mVUthrowHardwareDeficiency(const wxChar* extFail, int vuIndex)
}
// Only run this once per VU! ;)
static __ri void mVUinit(int vuIndex) {
void microVU::init(uint vuIndex) {
if(!x86caps.hasMultimediaExtensions) mVUthrowHardwareDeficiency( L"MMX", vuIndex );
if(!x86caps.hasStreamingSIMDExtensions) mVUthrowHardwareDeficiency( L"SSE", vuIndex );
if(!x86caps.hasStreamingSIMD2Extensions) mVUthrowHardwareDeficiency( L"SSE2", vuIndex );
microVU* mVU = mVUx;
memzero(mVU->prog);
memzero(prog);
mVU->index = vuIndex;
mVU->cop2 = 0;
mVU->vuMemSize = (vuIndex ? 0x4000 : 0x1000);
mVU->microMemSize = (vuIndex ? 0x4000 : 0x1000);
mVU->progSize = (vuIndex ? 0x4000 : 0x1000) / 4;
mVU->progMemMask = mVU->progSize-1;
mVU->dispCache = NULL;
mVU->cache = NULL;
mVU->cacheSize = mVUcacheSize;
mVU->regAlloc = new microRegAlloc();
index = vuIndex;
cop2 = 0;
vuMemSize = (index ? 0x4000 : 0x1000);
microMemSize = (index ? 0x4000 : 0x1000);
progSize = (index ? 0x4000 : 0x1000) / 4;
progMemMask = progSize-1;
dispCache = NULL;
cache = NULL;
cacheSize = mVUcacheSize;
regAlloc = new microRegAlloc(this);
for (u32 i = 0; i < (mVU->progSize / 2); i++) {
mVU->prog.prog[i] = new deque<microProgram*>();
for (u32 i = 0; i < (progSize / 2); i++) {
prog.prog[i] = new deque<microProgram*>();
}
mVU->dispCache = SysMmapEx(0, mVUdispCacheSize, 0, (mVU->index ? "Micro VU1 Dispatcher" : "Micro VU0 Dispatcher"));
if (!mVU->dispCache) throw Exception::OutOfMemory( mVU->index ? L"Micro VU1 Dispatcher" : L"Micro VU0 Dispatcher" );
memset(mVU->dispCache, 0xcc, mVUdispCacheSize);
dispCache = SysMmapEx(0, mVUdispCacheSize, 0, (index ? "Micro VU1 Dispatcher" : "Micro VU0 Dispatcher"));
if (!dispCache) throw Exception::OutOfMemory( index ? L"Micro VU1 Dispatcher" : L"Micro VU0 Dispatcher" );
memset(dispCache, 0xcc, mVUdispCacheSize);
// Allocates rec-cache and calls mVUreset()
mVUresizeCache(mVU, mVU->cacheSize + mVUcacheSafeZone);
mVUresizeCache(this, cacheSize + mVUcacheSafeZone);
//if (vuIndex) gen_memcpy_vibes();
}
// Resets Rec Data
// If vuRegsPtr is NUL, the current regs pointer assigned to the VU compiler is assumed.
static __fi void mVUreset(mV, VURegs* vuRegsPtr) {
void microVU::reset() {
static bool dispatchersGenerated = false;
if (!vuRegsPtr) vuRegsPtr = mVU->regs;
if (!dispatchersGenerated || (mVU->regs != vuRegsPtr))
{
// Setup Entrance/Exit Points
// These must be rebuilt whenever the vuRegsPtr has changed.
dispatchersGenerated = true;
mVU->regs = vuRegsPtr;
x86SetPtr(mVU->dispCache);
mVUdispatcherA(mVU);
mVUdispatcherB(mVU);
x86SetPtr(dispCache);
mVUdispatcherA(this);
mVUdispatcherB(this);
mVUemitSearch();
}
// Clear All Program Data
//memset(&mVU->prog, 0, sizeof(mVU->prog));
memset(&mVU->prog.lpState, 0, sizeof(mVU->prog.lpState));
//memset(&prog, 0, sizeof(prog));
memset(&prog.lpState, 0, sizeof(prog.lpState));
if (IsDevBuild) { // Release builds shouldn't need this
memset(mVU->cache, 0xcc, mVU->cacheSize);
memset(cache, 0xcc, cacheSize);
}
// Program Variables
mVU->prog.cleared = 1;
mVU->prog.isSame = -1;
mVU->prog.cur = NULL;
mVU->prog.total = 0;
mVU->prog.curFrame = 0;
prog.cleared = 1;
prog.isSame = -1;
prog.cur = NULL;
prog.total = 0;
prog.curFrame = 0;
// Setup Dynarec Cache Limits for Each Program
u8* z = mVU->cache;
mVU->prog.x86start = z;
mVU->prog.x86ptr = z;
mVU->prog.x86end = (u8*)((uptr)z + (uptr)(mVU->cacheSize - mVUcacheSafeZone)); // "Safe Zone"
u8* z = cache;
prog.x86start = z;
prog.x86ptr = z;
prog.x86end = (u8*)((uptr)z + (uptr)(cacheSize - mVUcacheSafeZone)); // "Safe Zone"
for (u32 i = 0; i < (mVU->progSize / 2); i++) {
deque<microProgram*>::iterator it(mVU->prog.prog[i]->begin());
for ( ; it != mVU->prog.prog[i]->end(); ++it) {
if (!isVU1) mVUdeleteProg<0>(it[0]);
else mVUdeleteProg<1>(it[0]);
for (u32 i = 0; i < (progSize / 2); i++) {
deque<microProgram*>::iterator it(prog.prog[i]->begin());
for ( ; it != prog.prog[i]->end(); ++it) {
if (index) mVUdeleteProg<1>(it[0]);
else mVUdeleteProg<0>(it[0]);
}
mVU->prog.prog[i]->clear();
mVU->prog.quick[i].block = NULL;
mVU->prog.quick[i].prog = NULL;
prog.prog[i]->clear();
prog.quick[i].block = NULL;
prog.quick[i].prog = NULL;
}
}
// Free Allocated Resources
static __fi void mVUclose(mV) {
void microVU::close() {
if (mVU->dispCache) { HostSys::Munmap(mVU->dispCache, mVUdispCacheSize); mVU->dispCache = NULL; }
if (mVU->cache) { HostSys::Munmap(mVU->cache, mVU->cacheSize); mVU->cache = NULL; }
if (dispCache) { HostSys::Munmap(dispCache, mVUdispCacheSize); dispCache = NULL; }
if (cache) { HostSys::Munmap(cache, cacheSize); cache = NULL; }
// Delete Programs and Block Managers
for (u32 i = 0; i < (mVU->progSize / 2); i++) {
deque<microProgram*>::iterator it(mVU->prog.prog[i]->begin());
for ( ; it != mVU->prog.prog[i]->end(); ++it) {
if (!isVU1) mVUdeleteProg<0>(it[0]);
else mVUdeleteProg<1>(it[0]);
for (u32 i = 0; i < (progSize / 2); i++) {
deque<microProgram*>::iterator it(prog.prog[i]->begin());
for ( ; it != prog.prog[i]->end(); ++it) {
if (index) mVUdeleteProg<1>(it[0]);
else mVUdeleteProg<0>(it[0]);
}
safe_delete(mVU->prog.prog[i]);
safe_delete(prog.prog[i]);
}
}
@ -181,7 +183,7 @@ static void mVUresizeCache(mV, u32 size) {
// We can't grow the rec any larger, so just reset it and start over.
//(if we don't reset, the rec will eventually crash)
Console.WriteLn(Color_Magenta, "microVU%d: Cannot grow cache, size limit reached! [%dmb]. Resetting rec.", mVU->index, mVU->cacheSize/_1mb);
mVUreset(mVU);
mVU->reset();
return;
}
size = mVUcacheMaxSize;
@ -191,7 +193,7 @@ static void mVUresizeCache(mV, u32 size) {
u8* cache = SysMmapEx(0, size, 0, (mVU->index ? "Micro VU1 RecCache" : "Micro VU0 RecCache"));
if(!cache && !mVU->cache) throw Exception::OutOfMemory( wxsFormat( L"Micro VU%d recompiled code cache", mVU->index) );
if(!cache) { Console.Error("microVU%d Error - Cache Resize Failed...", mVU->index); mVUreset(mVU); return; }
if(!cache) { Console.Error("microVU%d Error - Cache Resize Failed...", mVU->index); mVU->reset(); return; }
if (mVU->cache) {
HostSys::Munmap(mVU->cache, mVU->cacheSize);
ProfilerTerminateSource(isVU1?"mVU1 Rec":"mVU0 Rec");
@ -200,7 +202,7 @@ static void mVUresizeCache(mV, u32 size) {
mVU->cache = cache;
mVU->cacheSize = size;
ProfilerRegisterSource(isVU1?"mVU1 Rec":"mVU0 Rec", mVU->cache, mVU->cacheSize);
mVUreset(mVU);
mVU->reset();
}
// Clears Block Data in specified range
@ -254,8 +256,8 @@ _mVUt __fi microProgram* mVUcreateProg(int startPC) {
// Caches Micro Program
_mVUt __fi void mVUcacheProg(microProgram& prog) {
microVU* mVU = mVUx;
if (!vuIndex) memcpy_const(prog.data, mVU->regs->Micro, 0x1000);
else memcpy_const(prog.data, mVU->regs->Micro, 0x4000);
if (!vuIndex) memcpy_const(prog.data, mVU->regs().Micro, 0x1000);
else memcpy_const(prog.data, mVU->regs().Micro, 0x4000);
mVUdumpProg(prog);
}
@ -265,17 +267,17 @@ _mVUt __fi bool mVUcmpPartial(microProgram& prog) {
deque<microRange>::const_iterator it(prog.ranges->begin());
for ( ; it != prog.ranges->end(); ++it) {
if((it[0].start<0)||(it[0].end<0)) { DevCon.Error("microVU%d: Negative Range![%d][%d]", mVU->index, it[0].start, it[0].end); }
if (memcmp_mmx(cmpOffset(prog.data), cmpOffset(mVU->regs->Micro), ((it[0].end + 8) - it[0].start))) {
if (memcmp_mmx(cmpOffset(prog.data), cmpOffset(mVU->regs().Micro), ((it[0].end + 8) - it[0].start))) {
return 0;
}
}
return 1;
}
// Compare Cached microProgram to mVU->regs->Micro
// Compare Cached microProgram to mVU->regs().Micro
_mVUt __fi bool mVUcmpProg(microProgram& prog, const bool cmpWholeProg) {
microVU* mVU = mVUx;
if ((cmpWholeProg && !memcmp_mmx((u8*)prog.data, mVU->regs->Micro, mVU->microMemSize))
if ((cmpWholeProg && !memcmp_mmx((u8*)prog.data, mVU->regs().Micro, mVU->microMemSize))
|| (!cmpWholeProg && mVUcmpPartial<vuIndex>(prog))) {
mVU->prog.cleared = 0;
mVU->prog.cur = &prog;
@ -334,14 +336,14 @@ void recMicroVU0::Allocate() {
if(!m_AllocCount) {
m_AllocCount++;
if (AtomicExchange(mvu0_allocated, 1) == 0)
mVUinit(0);
microVU0.init(0);
}
}
void recMicroVU1::Allocate() {
if(!m_AllocCount) {
m_AllocCount++;
if (AtomicExchange(mvu1_allocated, 1) == 0)
mVUinit(1);
microVU1.init(1);
}
}
@ -349,24 +351,24 @@ void recMicroVU0::Shutdown() throw() {
if (m_AllocCount > 0) {
m_AllocCount--;
if (AtomicExchange(mvu0_allocated, 0) == 1)
mVUclose(&microVU0);
microVU0.close();
}
}
void recMicroVU1::Shutdown() throw() {
if (m_AllocCount > 0) {
m_AllocCount--;
if (AtomicExchange(mvu1_allocated, 0) == 1)
mVUclose(&microVU1);
microVU1.close();
}
}
void recMicroVU0::Reset() {
if(!pxAssertDev(m_AllocCount, "MicroVU0 CPU Provider has not been allocated prior to reset!")) return;
mVUreset(&microVU0, &VU0);
microVU0.reset();
}
void recMicroVU1::Reset() {
if(!pxAssertDev(m_AllocCount, "MicroVU1 CPU Provider has not been allocated prior to reset!")) return;
mVUreset(&microVU1, &VU1);
microVU1.reset();
}
void recMicroVU0::Execute(u32 cycles) {

View File

@ -145,7 +145,7 @@ struct microProgManager {
microProgramQuick quick[mProgSize/2]; // Quick reference to valid microPrograms for current execution
microProgram* cur; // Pointer to currently running MicroProgram
int total; // Total Number of valid MicroPrograms
int isSame; // Current cached microProgram is Exact Same program as mVU->regs->Micro (-1 = unknown, 0 = No, 1 = Yes)
int isSame; // Current cached microProgram is Exact Same program as mVU->regs().Micro (-1 = unknown, 0 = No, 1 = Yes)
int cleared; // Micro Program is Indeterminate so must be searched for (and if no matches are found then recompile a new one)
u32 curFrame; // Frame Counter
u8* x86ptr; // Pointer to program's recompilation code
@ -155,10 +155,10 @@ struct microProgManager {
};
#define mVUdispCacheSize (0x1000) // Dispatcher Cache Size
#define mVUcacheSize ((mVU->index) ? (_1mb * 17) : (_1mb * 7)) // Initial Size (Excluding Safe-Zone)
#define mVUcacheSize ((index) ? (_1mb * 17) : (_1mb * 7)) // Initial Size (Excluding Safe-Zone)
#define mVUcacheMaxSize ((mVU->index) ? (_1mb * 100) : (_1mb * 50)) // Max Size allowed to grow to
#define mVUcacheGrowBy ((mVU->index) ? (_1mb * 15) : (_1mb * 10)) // Grows by this amount
#define mVUcacheSafeZone ((mVU->index) ? (_1mb * 3) : (_1mb * 3)) // Safe-Zone for last program
#define mVUcacheSafeZone ((index) ? (_1mb * 3) : (_1mb * 3)) // Safe-Zone for last program
struct microVU {
@ -179,7 +179,6 @@ struct microVU {
ScopedPtr<microRegAlloc> regAlloc; // Reg Alloc Class
ScopedPtr<AsciiFile> logFile; // Log File Pointer
VURegs* regs; // VU Regs Struct
u8* cache; // Dynarec Cache Start (where we will start writing the recompiled code to)
u8* dispCache; // Dispatchers Cache (where startFunct and exitFunct are written to)
u8* startFunct; // Ptr Function to the Start code for recompiled programs
@ -196,6 +195,13 @@ struct microVU {
u32 totalCycles; // Total Cycles that mVU is expected to run for
u32 cycles; // Cycles Counter
VURegs& regs() const { return ::vuRegs[index]; }
VIFregisters& getVifRegs() const { return regs().GetVifRegs(); }
__fi REG_VI& getVI(uint reg) const { return regs().VI[reg]; }
__fi VECTOR& getVF(uint reg) const { return regs().VF[reg]; }
__fi s16 Imm5() const { return ((code & 0x400) ? 0xfff0 : 0) | ((code >> 6) & 0xf); }
__fi s32 Imm11() const { return (code & 0x400) ? (0xfffffc00 | (code & 0x3ff)) : (code & 0x3ff); }
__fi u32 Imm12() const { return (((code >> 21) & 0x1) << 11) | (code & 0x7ff); }
@ -208,7 +214,7 @@ struct microVU {
{
prog.IRinfo.curPC += x;
prog.IRinfo.curPC &= progMemMask;
code = ((u32*)regs->Micro)[prog.IRinfo.curPC];
code = ((u32*)regs().Micro)[prog.IRinfo.curPC];
}
__ri uint getBranchAddr() const
@ -222,6 +228,16 @@ struct microVU {
pxAssumeDev((prog.IRinfo.curPC & 1) == 0, "microVU recompiler: Upper instructions cannot have valid branch addresses.");
return (((prog.IRinfo.curPC + 4) + (Imm11() * 2)) & progMemMask) * 4;
}
__ri void loadIreg(const xmm& reg, int xyzw)
{
xMOVSSZX(reg, ptr32[&getVI(REG_I)]);
if (!_XYZWss(xyzw)) xSHUF.PS(reg, reg, 0);
}
void init(uint vuIndex);
void reset();
void close();
};
// microVU rec structs
@ -232,9 +248,6 @@ extern __aligned16 microVU microVU1;
int mVUdebugNow = 0;
// Main Functions
static void mVUinit(int);
static void mVUreset(mV, VURegs* vuRegsPtr = NULL);
static void mVUclose(mV);
static void mVUclear(mV, u32, u32);
static void mVUresizeCache(mV, u32);
static void* mVUblockFetch(microVU* mVU, u32 startPC, uptr pState);
@ -257,18 +270,3 @@ extern void* __fastcall mVUexecuteVU1(u32 startPC, u32 cycles);
// recCall Function Pointer
typedef void (__fastcall *mVUrecCall)(u32, u32);
// Include all the *.inl files (Needed because C++ sucks with templates and *.cpp files)
#include "microVU_Clamp.inl"
#include "microVU_Misc.inl"
#include "microVU_Log.inl"
#include "microVU_Analyze.inl"
#include "microVU_Alloc.inl"
#include "microVU_Upper.inl"
#include "microVU_Lower.inl"
#include "microVU_Tables.inl"
#include "microVU_Flags.inl"
#include "microVU_Branch.inl"
#include "microVU_Compile.inl"
#include "microVU_Execute.inl"
#include "microVU_Macro.inl"

View File

@ -110,19 +110,19 @@ __fi void mVUallocMFLAGb(mV, const x32& reg, int fInstance)
{
//xAND(reg, 0xffff);
if (fInstance < 4) xMOV(ptr32[&mVU->macFlag[fInstance]], reg); // microVU
else xMOV(ptr32[&mVU->regs->VI[REG_MAC_FLAG].UL], reg); // macroVU
else xMOV(ptr32[&mVU->regs().VI[REG_MAC_FLAG].UL], reg); // macroVU
}
__fi void mVUallocCFLAGa(mV, const x32& reg, int fInstance)
{
if (fInstance < 4) xMOV(reg, ptr32[&mVU->clipFlag[fInstance]]); // microVU
else xMOV(reg, ptr32[&mVU->regs->VI[REG_CLIP_FLAG].UL]); // macroVU
else xMOV(reg, ptr32[&mVU->regs().VI[REG_CLIP_FLAG].UL]); // macroVU
}
__fi void mVUallocCFLAGb(mV, const x32& reg, int fInstance)
{
if (fInstance < 4) xMOV(ptr32[&mVU->clipFlag[fInstance]], reg); // microVU
else xMOV(ptr32[&mVU->regs->VI[REG_CLIP_FLAG].UL], reg); // macroVU
else xMOV(ptr32[&mVU->regs().VI[REG_CLIP_FLAG].UL], reg); // macroVU
}
//------------------------------------------------------------------
@ -135,19 +135,19 @@ __ri void mVUallocVIa(mV, const x32& GPRreg, int _reg_, bool signext = false)
xXOR(GPRreg, GPRreg);
else
if (signext)
xMOVSX(GPRreg, ptr16[&mVU->regs->VI[_reg_].SL]);
xMOVSX(GPRreg, ptr16[&mVU->regs().VI[_reg_].SL]);
else
xMOVZX(GPRreg, ptr16[&mVU->regs->VI[_reg_].UL]);
xMOVZX(GPRreg, ptr16[&mVU->regs().VI[_reg_].UL]);
}
__ri void mVUallocVIb(mV, const x32& GPRreg, int _reg_)
{
if (mVUlow.backupVI) { // Backs up reg to memory (used when VI is modified b4 a branch)
xMOVZX(gprT3, ptr16[&mVU->regs->VI[_reg_].UL]);
xMOVZX(gprT3, ptr16[&mVU->regs().VI[_reg_].UL]);
xMOV (ptr32[&mVU->VIbackup], gprT3);
}
if (_reg_ == 0) { return; }
else if (_reg_ < 16) { xMOV(ptr16[&mVU->regs->VI[_reg_].UL], xRegister16(GPRreg.Id)); }
else if (_reg_ < 16) { xMOV(ptr16[&mVU->regs().VI[_reg_].UL], xRegister16(GPRreg.Id)); }
}
//------------------------------------------------------------------

View File

@ -56,31 +56,31 @@ void mVUendProgram(mV, microFlagCycles* mFC, int isEbit) {
// Save P/Q Regs
if (qInst) { xPSHUF.D(xmmPQ, xmmPQ, 0xe5); }
xMOVSS(ptr32[&mVU->regs->VI[REG_Q].UL], xmmPQ);
xMOVSS(ptr32[&mVU->regs().VI[REG_Q].UL], xmmPQ);
if (isVU1) {
xPSHUF.D(xmmPQ, xmmPQ, pInst ? 3 : 2);
xMOVSS(ptr32[&mVU->regs->VI[REG_P].UL], xmmPQ);
xMOVSS(ptr32[&mVU->regs().VI[REG_P].UL], xmmPQ);
}
// Save Flag Instances
#if 1 // CHECK_MACROVU0 - Always on now
xMOV(ptr32[&mVU->regs->VI[REG_STATUS_FLAG].UL], getFlagReg(fStatus));
xMOV(ptr32[&mVU->regs().VI[REG_STATUS_FLAG].UL], getFlagReg(fStatus));
#else
mVUallocSFLAGc(gprT1, gprT2, fStatus);
xMOV(ptr32[&mVU->regs->VI[REG_STATUS_FLAG].UL], gprT1);
xMOV(ptr32[&mVU->regs().VI[REG_STATUS_FLAG].UL], gprT1);
#endif
mVUallocMFLAGa(mVU, gprT1, fMac);
mVUallocCFLAGa(mVU, gprT2, fClip);
xMOV(ptr32[&mVU->regs->VI[REG_MAC_FLAG].UL], gprT1);
xMOV(ptr32[&mVU->regs->VI[REG_CLIP_FLAG].UL], gprT2);
xMOV(ptr32[&mVU->regs().VI[REG_MAC_FLAG].UL], gprT1);
xMOV(ptr32[&mVU->regs().VI[REG_CLIP_FLAG].UL], gprT2);
if (isEbit || isVU1) { // Clear 'is busy' Flags
xAND(ptr32[&VU0.VI[REG_VPU_STAT].UL], (isVU1 ? ~0x100 : ~0x001)); // VBS0/VBS1 flag
xAND(ptr32[&mVU->regs->vifRegs->stat], ~VIF1_STAT_VEW); // Clear VU 'is busy' signal for vif
xAND(ptr32[&mVU->getVifRegs().stat], ~VIF1_STAT_VEW); // Clear VU 'is busy' signal for vif
}
if (isEbit != 2) { // Save PC, and Jump to Exit Point
xMOV(ptr32[&mVU->regs->VI[REG_TPC].UL], xPC);
xMOV(ptr32[&mVU->regs().VI[REG_TPC].UL], xPC);
xJMP(mVU->exitFunct);
}
}
@ -137,12 +137,12 @@ void condBranch(mV, microFlagCycles& mFC, int JMPcc) {
mVUendProgram(mVU, &mFC, 2);
xForwardJump8 eJMP((JccComparisonType)JMPcc);
incPC(1); // Set PC to First instruction of Non-Taken Side
xMOV(ptr32[&mVU->regs->VI[REG_TPC].UL], xPC);
xMOV(ptr32[&mVU->regs().VI[REG_TPC].UL], xPC);
xJMP(mVU->exitFunct);
eJMP.SetTarget();
incPC(-4); // Go Back to Branch Opcode to get branchAddr
iPC = branchAddr/4;
xMOV(ptr32[&mVU->regs->VI[REG_TPC].UL], xPC);
xMOV(ptr32[&mVU->regs().VI[REG_TPC].UL], xPC);
xJMP(mVU->exitFunct);
return;
}
@ -190,7 +190,7 @@ void normJump(mV, microFlagCycles& mFC) {
if (mVUup.eBit) { // E-bit Jump
mVUendProgram(mVU, &mFC, 2);
xMOV(gprT1, ptr32[&mVU->branch]);
xMOV(ptr32[&mVU->regs->VI[REG_TPC].UL], gprT1);
xMOV(ptr32[&mVU->regs().VI[REG_TPC].UL], gprT1);
xJMP(mVU->exitFunct);
}
else normJumpCompile(mVU, mFC, 0);

View File

@ -45,7 +45,7 @@ static void __fastcall mVUprintPC2(u32 PC) { Console.WriteLn("Block End PC = 0
// Used by mVUsetupRange
static __fi void mVUcheckIsSame(mV) {
if (mVU->prog.isSame == -1) {
mVU->prog.isSame = !memcmp_mmx((u8*)mVUcurProg.data, mVU->regs->Micro, mVU->microMemSize);
mVU->prog.isSame = !memcmp_mmx((u8*)mVUcurProg.data, mVU->regs().Micro, mVU->microMemSize);
}
if (mVU->prog.isSame == 0) {
if (!isVU1) mVUcacheProg<0>(*mVU->prog.cur);
@ -126,7 +126,7 @@ static void doIbit(mV) {
}
else tempI = curI;
xMOV(ptr32[&mVU->regs->VI[REG_I].UL], tempI);
xMOV(ptr32[&mVU->regs().VI[REG_I].UL], tempI);
incPC(1);
}
}
@ -328,7 +328,7 @@ static void mVUtestCycles(microVU* mVU) {
xCMP(ptr32[&mVU->cycles], 0);
xForwardJG32 skip;
if (isVU0) {
// TEST32ItoM((uptr)&mVU->regs->flags, VUFLAG_MFLAGSET);
// TEST32ItoM((uptr)&mVU->regs().flags, VUFLAG_MFLAGSET);
// xFowardJZ32 vu0jmp;
// xMOV(gprT2, (uptr)mVU);
// xCALL(mVUwarning0); // VU0 is allowed early exit for COP2 Interlock Simulation
@ -394,7 +394,7 @@ void* mVUcompile(microVU* mVU, u32 startPC, uptr pState) {
// First Pass
iPC = startPC / 4;
mVUsetupRange(mVU, startPC, 1); // Setup Program Bounds/Range
mVU->regAlloc->reset(mVU->regs); // Reset regAlloc
mVU->regAlloc->reset(); // Reset regAlloc
mVUinitFirstPass(mVU, pState, thisPtr);
for (int branch = 0; mVUcount < endCount; mVUcount++) {
incPC(1);
@ -433,7 +433,7 @@ void* mVUcompile(microVU* mVU, u32 startPC, uptr pState) {
u32 x = 0;
for (; x < endCount; x++) {
if (mVUinfo.isEOB) { handleBadOp(mVU, x); x = 0xffff; }
if (mVUup.mBit) { xOR(ptr32[&mVU->regs->flags], VUFLAG_MFLAGSET); }
if (mVUup.mBit) { xOR(ptr32[&mVU->regs().flags], VUFLAG_MFLAGSET); }
if (mVUlow.isNOP) { incPC(1); doUpperOp(); doIbit(mVU); }
else if (!mVUinfo.swapOps) { incPC(1); doUpperOp(); doLowerOp(); }
else { doSwapOp(mVU); }

View File

@ -43,24 +43,24 @@ void mVUdispatcherA(mV) {
// Load Regs
#if 1 // CHECK_MACROVU0 - Always on now
xMOV(gprF0, ptr32[&mVU->regs->VI[REG_STATUS_FLAG].UL]);
xMOV(gprF0, ptr32[&mVU->regs().VI[REG_STATUS_FLAG].UL]);
xMOV(gprF1, gprF0);
xMOV(gprF2, gprF0);
xMOV(gprF3, gprF0);
#else
mVUallocSFLAGd((uptr)&mVU->regs->VI[REG_STATUS_FLAG].UL, 1);
mVUallocSFLAGd((uptr)&mVU->regs().VI[REG_STATUS_FLAG].UL, 1);
#endif
xMOVAPS(xmmT1, ptr128[&mVU->regs->VI[REG_MAC_FLAG].UL]);
xMOVAPS(xmmT1, ptr128[&mVU->regs().VI[REG_MAC_FLAG].UL]);
xSHUF.PS(xmmT1, xmmT1, 0);
xMOVAPS(ptr128[mVU->macFlag], xmmT1);
xMOVAPS(xmmT1, ptr128[&mVU->regs->VI[REG_CLIP_FLAG].UL]);
xMOVAPS(xmmT1, ptr128[&mVU->regs().VI[REG_CLIP_FLAG].UL]);
xSHUF.PS(xmmT1, xmmT1, 0);
xMOVAPS(ptr128[mVU->clipFlag], xmmT1);
xMOVAPS(xmmT1, ptr128[&mVU->regs->VI[REG_P].UL]);
xMOVAPS(xmmPQ, ptr128[&mVU->regs->VI[REG_Q].UL]);
xMOVAPS(xmmT1, ptr128[&mVU->regs().VI[REG_P].UL]);
xMOVAPS(xmmPQ, ptr128[&mVU->regs().VI[REG_Q].UL]);
xSHUF.PS(xmmPQ, xmmT1, 0); // wzyx = PPQQ
// Jump to Recompiled Code Block
@ -119,12 +119,12 @@ _mVUt void* __fastcall mVUexecute(u32 startPC, u32 cycles) {
_mVUt void mVUcleanUp() {
microVU* mVU = mVUx;
//mVUprint("microVU: Program exited successfully!");
//mVUprint("microVU: VF0 = {%x,%x,%x,%x}", mVU->regs->VF[0].UL[0], mVU->regs->VF[0].UL[1], mVU->regs->VF[0].UL[2], mVU->regs->VF[0].UL[3]);
//mVUprint("microVU: VI0 = %x", mVU->regs->VI[0].UL);
//mVUprint("microVU: VF0 = {%x,%x,%x,%x}", mVU->regs().VF[0].UL[0], mVU->regs().VF[0].UL[1], mVU->regs().VF[0].UL[2], mVU->regs().VF[0].UL[3]);
//mVUprint("microVU: VI0 = %x", mVU->regs().VI[0].UL);
mVU->prog.x86ptr = x86Ptr;
mVUcacheCheck(x86Ptr, mVU->prog.x86start, (uptr)(mVU->prog.x86end - mVU->prog.x86start));
mVU->cycles = mVU->totalCycles - mVU->cycles;
mVU->regs->cycle += mVU->cycles;
mVU->regs().cycle += mVU->cycles;
cpuRegs.cycle += ((mVU->cycles < 3000) ? mVU->cycles : 3000) * EmuConfig.Speedhacks.VUCycleSteal;
//static int ax = 0; ax++;
//if (!(ax % 100000)) {

View File

@ -172,36 +172,18 @@ struct microMapXMM {
#define xmmTotal 7 // Don't allocate PQ?
class microRegAlloc {
private:
protected:
microMapXMM xmmMap[xmmTotal];
VURegs* vuRegs;
int counter;
int findFreeRegRec(int startIdx) {
for (int i = startIdx; i < xmmTotal; i++) {
if (!xmmMap[i].isNeeded) {
int x = findFreeRegRec(i+1);
if (x == -1) return i;
return ((xmmMap[i].count < xmmMap[x].count) ? i : x);
}
}
return -1;
}
int findFreeReg() {
for (int i = 0; i < xmmTotal; i++) {
if (!xmmMap[i].isNeeded && (xmmMap[i].VFreg < 0)) {
return i; // Reg is not needed and was a temp reg
}
}
int x = findFreeRegRec(0);
pxAssumeDev( x >= 0, "microVU register allocation failure!" );
return x;
}
microVU* mVU;
int findFreeRegRec(int startIdx);
int findFreeReg();
public:
microRegAlloc() { }
microRegAlloc(microVU* _mVU);
void reset(VURegs* vuRegsPtr) {
vuRegs = vuRegsPtr;
void reset() {
for (int i = 0; i < xmmTotal; i++) {
clearReg(i);
}
@ -213,132 +195,14 @@ public:
if (clearState) clearReg(i);
}
}
void clearReg(int regId);
void clearReg(const xmm& reg) { clearReg(reg.Id); }
void clearReg(int regId) {
microMapXMM& clear( xmmMap[regId] );
clear.VFreg = -1;
clear.count = 0;
clear.xyzw = 0;
clear.isNeeded = 0;
}
void clearRegVF(int VFreg) {
for (int i = 0; i < xmmTotal; i++) {
if (xmmMap[i].VFreg == VFreg) clearReg(i);
}
}
void writeBackReg(const xmm& reg, bool invalidateRegs = 1) {
microMapXMM& write( xmmMap[reg.Id] );
if ((write.VFreg > 0) && write.xyzw) { // Reg was modified and not Temp or vf0
if (write.VFreg == 33) xMOVSS(ptr32[&vuRegs->VI[REG_I].UL], reg);
else if (write.VFreg == 32) mVUsaveReg(reg, ptr[&vuRegs->ACC.UL[0]], write.xyzw, 1);
else mVUsaveReg(reg, ptr[&vuRegs->VF[write.VFreg].UL[0]], write.xyzw, 1);
if (invalidateRegs) {
for (int i = 0; i < xmmTotal; i++) {
microMapXMM& imap (xmmMap[i]);
if ((i == reg.Id) || imap.isNeeded) continue;
if (imap.VFreg == write.VFreg) {
if (imap.xyzw && imap.xyzw < 0xf) DevCon.Error("microVU Error: writeBackReg() [%d]", imap.VFreg);
clearReg(i); // Invalidate any Cached Regs of same vf Reg
}
}
}
if (write.xyzw == 0xf) { // Make Cached Reg if All Vectors were Modified
write.count = counter;
write.xyzw = 0;
write.isNeeded = 0;
return;
}
}
clearReg(reg); // Clear Reg
}
void clearNeeded(const xmm& reg)
{
if ((reg.Id < 0) || (reg.Id >= xmmTotal)) return;
microMapXMM& clear (xmmMap[reg.Id]);
clear.isNeeded = 0;
if (clear.xyzw) { // Reg was modified
if (clear.VFreg > 0) {
int mergeRegs = 0;
if (clear.xyzw < 0xf) { mergeRegs = 1; } // Try to merge partial writes
for (int i = 0; i < xmmTotal; i++) { // Invalidate any other read-only regs of same vfReg
if (i == reg.Id) continue;
microMapXMM& imap (xmmMap[i]);
if (imap.VFreg == clear.VFreg) {
if (imap.xyzw && imap.xyzw < 0xf) DevCon.Error("microVU Error: clearNeeded() [%d]", imap.VFreg);
if (mergeRegs == 1) {
mVUmergeRegs(xmm(i), reg, clear.xyzw, 1);
imap.xyzw = 0xf;
imap.count = counter;
mergeRegs = 2;
}
else clearReg(i);
}
}
if (mergeRegs == 2) clearReg(reg); // Clear Current Reg if Merged
else if (mergeRegs) writeBackReg(reg); // Write Back Partial Writes if couldn't merge
}
else clearReg(reg); // If Reg was temp or vf0, then invalidate itself
}
}
const xmm& allocReg(int vfLoadReg = -1, int vfWriteReg = -1, int xyzw = 0, bool cloneWrite = 1) {
counter++;
if (vfLoadReg >= 0) { // Search For Cached Regs
for (int i = 0; i < xmmTotal; i++) {
const xmm& xmmi(xmm::GetInstance(i));
microMapXMM& imap (xmmMap[i]);
if ((imap.VFreg == vfLoadReg) && (!imap.xyzw // Reg Was Not Modified
|| (imap.VFreg && (imap.xyzw==0xf)))) { // Reg Had All Vectors Modified and != VF0
int z = i;
if (vfWriteReg >= 0) { // Reg will be modified
if (cloneWrite) { // Clone Reg so as not to use the same Cached Reg
z = findFreeReg();
const xmm& xmmz(xmm::GetInstance(z));
writeBackReg(xmmz);
if (z!=i && xyzw==8) xMOVAPS (xmmz, xmmi);
else if (xyzw == 4) xPSHUF.D(xmmz, xmmi, 1);
else if (xyzw == 2) xPSHUF.D(xmmz, xmmi, 2);
else if (xyzw == 1) xPSHUF.D(xmmz, xmmi, 3);
else if (z != i) xMOVAPS (xmmz, xmmi);
imap.count = counter; // Reg i was used, so update counter
}
else { // Don't clone reg, but shuffle to adjust for SS ops
if ((vfLoadReg != vfWriteReg) || (xyzw != 0xf)) { writeBackReg(xmmi); }
if (xyzw == 4) xPSHUF.D(xmmi, xmmi, 1);
else if (xyzw == 2) xPSHUF.D(xmmi, xmmi, 2);
else if (xyzw == 1) xPSHUF.D(xmmi, xmmi, 3);
}
xmmMap[z].VFreg = vfWriteReg;
xmmMap[z].xyzw = xyzw;
}
xmmMap[z].count = counter;
xmmMap[z].isNeeded = 1;
return xmm::GetInstance(z);
}
}
}
int x = findFreeReg();
const xmm& xmmx = xmm::GetInstance(x);
writeBackReg(xmmx);
if (vfWriteReg >= 0) { // Reg Will Be Modified (allow partial reg loading)
if ((vfLoadReg == 0) && !(xyzw & 1)) { xPXOR(xmmx, xmmx); }
else if (vfLoadReg == 33) mVUloadIreg(xmmx, xyzw, vuRegs);
else if (vfLoadReg == 32) mVUloadReg (xmmx, ptr[&vuRegs->ACC.UL[0]], xyzw);
else if (vfLoadReg >= 0) mVUloadReg (xmmx, ptr[&vuRegs->VF[vfLoadReg].UL[0]], xyzw);
xmmMap[x].VFreg = vfWriteReg;
xmmMap[x].xyzw = xyzw;
}
else { // Reg Will Not Be Modified (always load full reg for caching)
if (vfLoadReg == 33) mVUloadIreg(xmmx, 0xf, vuRegs);
else if (vfLoadReg == 32) xMOVAPS(xmmx, ptr128[&vuRegs->ACC.UL[0]]);
else if (vfLoadReg >= 0) xMOVAPS(xmmx, ptr128[&vuRegs->VF[vfLoadReg].UL[0]]);
xmmMap[x].VFreg = vfLoadReg;
xmmMap[x].xyzw = 0;
}
xmmMap[x].count = counter;
xmmMap[x].isNeeded = 1;
return xmmx;
}
void writeBackReg(const xmm& reg, bool invalidateRegs = 1);
void clearNeeded(const xmm& reg);
const xmm& allocReg(int vfLoadReg = -1, int vfWriteReg = -1, int xyzw = 0, bool cloneWrite = 1);
};

165
pcsx2/x86/microVU_IR.inl Normal file
View File

@ -0,0 +1,165 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 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 PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
int microRegAlloc::findFreeRegRec(int startIdx) {
for (int i = startIdx; i < xmmTotal; i++) {
if (!xmmMap[i].isNeeded) {
int x = findFreeRegRec(i+1);
if (x == -1) return i;
return ((xmmMap[i].count < xmmMap[x].count) ? i : x);
}
}
return -1;
}
int microRegAlloc::findFreeReg() {
for (int i = 0; i < xmmTotal; i++) {
if (!xmmMap[i].isNeeded && (xmmMap[i].VFreg < 0)) {
return i; // Reg is not needed and was a temp reg
}
}
int x = findFreeRegRec(0);
pxAssumeDev( x >= 0, "microVU register allocation failure!" );
return x;
}
microRegAlloc::microRegAlloc(microVU* _mVU) {
mVU = _mVU;
}
void microRegAlloc::clearReg(int regId) {
microMapXMM& clear( xmmMap[regId] );
clear.VFreg = -1;
clear.count = 0;
clear.xyzw = 0;
clear.isNeeded = 0;
}
void microRegAlloc::writeBackReg(const xmm& reg, bool invalidateRegs) {
microMapXMM& write( xmmMap[reg.Id] );
if ((write.VFreg > 0) && write.xyzw) { // Reg was modified and not Temp or vf0
if (write.VFreg == 33) xMOVSS(ptr32[&mVU->getVI(REG_I)], reg);
else if (write.VFreg == 32) mVUsaveReg(reg, ptr[&mVU->regs().ACC], write.xyzw, 1);
else mVUsaveReg(reg, ptr[&mVU->getVF(write.VFreg)], write.xyzw, 1);
if (invalidateRegs) {
for (int i = 0; i < xmmTotal; i++) {
microMapXMM& imap (xmmMap[i]);
if ((i == reg.Id) || imap.isNeeded) continue;
if (imap.VFreg == write.VFreg) {
if (imap.xyzw && imap.xyzw < 0xf) DevCon.Error("microVU Error: writeBackReg() [%d]", imap.VFreg);
clearReg(i); // Invalidate any Cached Regs of same vf Reg
}
}
}
if (write.xyzw == 0xf) { // Make Cached Reg if All Vectors were Modified
write.count = counter;
write.xyzw = 0;
write.isNeeded = 0;
return;
}
}
clearReg(reg); // Clear Reg
}
void microRegAlloc::clearNeeded(const xmm& reg)
{
if ((reg.Id < 0) || (reg.Id >= xmmTotal)) return;
microMapXMM& clear (xmmMap[reg.Id]);
clear.isNeeded = 0;
if (clear.xyzw) { // Reg was modified
if (clear.VFreg > 0) {
int mergeRegs = 0;
if (clear.xyzw < 0xf) { mergeRegs = 1; } // Try to merge partial writes
for (int i = 0; i < xmmTotal; i++) { // Invalidate any other read-only regs of same vfReg
if (i == reg.Id) continue;
microMapXMM& imap (xmmMap[i]);
if (imap.VFreg == clear.VFreg) {
if (imap.xyzw && imap.xyzw < 0xf) DevCon.Error("microVU Error: clearNeeded() [%d]", imap.VFreg);
if (mergeRegs == 1) {
mVUmergeRegs(xmm(i), reg, clear.xyzw, 1);
imap.xyzw = 0xf;
imap.count = counter;
mergeRegs = 2;
}
else clearReg(i);
}
}
if (mergeRegs == 2) clearReg(reg); // Clear Current Reg if Merged
else if (mergeRegs) writeBackReg(reg); // Write Back Partial Writes if couldn't merge
}
else clearReg(reg); // If Reg was temp or vf0, then invalidate itself
}
}
const xmm& microRegAlloc::allocReg(int vfLoadReg, int vfWriteReg, int xyzw, bool cloneWrite) {
counter++;
if (vfLoadReg >= 0) { // Search For Cached Regs
for (int i = 0; i < xmmTotal; i++) {
const xmm& xmmi(xmm::GetInstance(i));
microMapXMM& imap (xmmMap[i]);
if ((imap.VFreg == vfLoadReg) && (!imap.xyzw // Reg Was Not Modified
|| (imap.VFreg && (imap.xyzw==0xf)))) { // Reg Had All Vectors Modified and != VF0
int z = i;
if (vfWriteReg >= 0) { // Reg will be modified
if (cloneWrite) { // Clone Reg so as not to use the same Cached Reg
z = findFreeReg();
const xmm& xmmz(xmm::GetInstance(z));
writeBackReg(xmmz);
if (z!=i && xyzw==8) xMOVAPS (xmmz, xmmi);
else if (xyzw == 4) xPSHUF.D(xmmz, xmmi, 1);
else if (xyzw == 2) xPSHUF.D(xmmz, xmmi, 2);
else if (xyzw == 1) xPSHUF.D(xmmz, xmmi, 3);
else if (z != i) xMOVAPS (xmmz, xmmi);
imap.count = counter; // Reg i was used, so update counter
}
else { // Don't clone reg, but shuffle to adjust for SS ops
if ((vfLoadReg != vfWriteReg) || (xyzw != 0xf)) { writeBackReg(xmmi); }
if (xyzw == 4) xPSHUF.D(xmmi, xmmi, 1);
else if (xyzw == 2) xPSHUF.D(xmmi, xmmi, 2);
else if (xyzw == 1) xPSHUF.D(xmmi, xmmi, 3);
}
xmmMap[z].VFreg = vfWriteReg;
xmmMap[z].xyzw = xyzw;
}
xmmMap[z].count = counter;
xmmMap[z].isNeeded = 1;
return xmm::GetInstance(z);
}
}
}
int x = findFreeReg();
const xmm& xmmx = xmm::GetInstance(x);
writeBackReg(xmmx);
if (vfWriteReg >= 0) { // Reg Will Be Modified (allow partial reg loading)
if ((vfLoadReg == 0) && !(xyzw & 1)) { xPXOR(xmmx, xmmx); }
else if (vfLoadReg == 33) mVU->loadIreg(xmmx, xyzw);
else if (vfLoadReg == 32) mVUloadReg (xmmx, ptr[&mVU->regs().ACC], xyzw);
else if (vfLoadReg >= 0) mVUloadReg (xmmx, ptr[&mVU->getVF(vfLoadReg)], xyzw);
xmmMap[x].VFreg = vfWriteReg;
xmmMap[x].xyzw = xyzw;
}
else { // Reg Will Not Be Modified (always load full reg for caching)
if (vfLoadReg == 33) mVU->loadIreg(xmmx, 0xf);
else if (vfLoadReg == 32) xMOVAPS(xmmx, ptr128[&mVU->regs().ACC]);
else if (vfLoadReg >= 0) xMOVAPS(xmmx, ptr128[&mVU->getVF(vfLoadReg)]);
xmmMap[x].VFreg = vfLoadReg;
xmmMap[x].xyzw = 0;
}
xmmMap[x].count = counter;
xmmMap[x].isNeeded = 1;
return xmmx;
}

View File

@ -778,7 +778,7 @@ mVUop(mVU_MTIR) {
mVUop(mVU_ILW) {
pass1 { if (!_It_) { mVUlow.isNOP = 1; } analyzeVIreg1(_Is_, mVUlow.VI_read[0]); analyzeVIreg2(_It_, mVUlow.VI_write, 4); }
pass2 {
xAddressVoid ptr(mVU->regs->Mem + offsetSS);
xAddressVoid ptr(mVU->regs().Mem + offsetSS);
if (_Is_) {
mVUallocVIa(mVU, gprT2, _Is_);
xADD(gprT2, _Imm11_);
@ -796,7 +796,7 @@ mVUop(mVU_ILW) {
mVUop(mVU_ILWR) {
pass1 { if (!_It_) { mVUlow.isNOP = 1; } analyzeVIreg1(_Is_, mVUlow.VI_read[0]); analyzeVIreg2(_It_, mVUlow.VI_write, 4); }
pass2 {
xAddressVoid ptr(mVU->regs->Mem + offsetSS);
xAddressVoid ptr(mVU->regs().Mem + offsetSS);
if (_Is_) {
mVUallocVIa(mVU, gprT2, _Is_);
mVUaddrFix (mVU, gprT2);
@ -815,7 +815,7 @@ mVUop(mVU_ILWR) {
mVUop(mVU_ISW) {
pass1 { analyzeVIreg1(_Is_, mVUlow.VI_read[0]); analyzeVIreg1(_It_, mVUlow.VI_read[1]); }
pass2 {
xAddressVoid ptr(mVU->regs->Mem);
xAddressVoid ptr(mVU->regs().Mem);
if (_Is_) {
mVUallocVIa(mVU, gprT2, _Is_);
xADD(gprT2, _Imm11_);
@ -836,7 +836,7 @@ mVUop(mVU_ISW) {
mVUop(mVU_ISWR) {
pass1 { analyzeVIreg1(_Is_, mVUlow.VI_read[0]); analyzeVIreg1(_It_, mVUlow.VI_read[1]); }
pass2 {
xAddressVoid ptr(mVU->regs->Mem);
xAddressVoid ptr(mVU->regs().Mem);
if (_Is_) {
mVUallocVIa(mVU, gprT2, _Is_);
mVUaddrFix (mVU, gprT2);
@ -858,7 +858,7 @@ mVUop(mVU_ISWR) {
mVUop(mVU_LQ) {
pass1 { mVUanalyzeLQ(mVU, _Ft_, _Is_, 0); }
pass2 {
xAddressVoid ptr(mVU->regs->Mem);
xAddressVoid ptr(mVU->regs().Mem);
if (_Is_) {
mVUallocVIa(mVU, gprT2, _Is_);
xADD(gprT2, _Imm11_);
@ -877,7 +877,7 @@ mVUop(mVU_LQ) {
mVUop(mVU_LQD) {
pass1 { mVUanalyzeLQ(mVU, _Ft_, _Is_, 1); }
pass2 {
xAddressVoid ptr(mVU->regs->Mem);
xAddressVoid ptr(mVU->regs().Mem);
if (_Is_) {
mVUallocVIa(mVU, gprT2, _Is_);
xSUB(gprT2b, 1);
@ -897,7 +897,7 @@ mVUop(mVU_LQD) {
mVUop(mVU_LQI) {
pass1 { mVUanalyzeLQ(mVU, _Ft_, _Is_, 1); }
pass2 {
xAddressVoid ptr(mVU->regs->Mem);
xAddressVoid ptr(mVU->regs().Mem);
if (_Is_) {
mVUallocVIa(mVU, gprT1, _Is_);
xMOV(gprT2, gprT1);
@ -922,7 +922,7 @@ mVUop(mVU_LQI) {
mVUop(mVU_SQ) {
pass1 { mVUanalyzeSQ(mVU, _Fs_, _It_, 0); }
pass2 {
xAddressVoid ptr(mVU->regs->Mem);
xAddressVoid ptr(mVU->regs().Mem);
if (_It_) {
mVUallocVIa(mVU, gprT2, _It_);
xADD(gprT2, _Imm11_);
@ -941,7 +941,7 @@ mVUop(mVU_SQ) {
mVUop(mVU_SQD) {
pass1 { mVUanalyzeSQ(mVU, _Fs_, _It_, 1); }
pass2 {
xAddressVoid ptr(mVU->regs->Mem);
xAddressVoid ptr(mVU->regs().Mem);
if (_It_) {
mVUallocVIa(mVU, gprT2, _It_);
xSUB(gprT2b, 1);
@ -959,7 +959,7 @@ mVUop(mVU_SQD) {
mVUop(mVU_SQI) {
pass1 { mVUanalyzeSQ(mVU, _Fs_, _It_, 1); }
pass2 {
xAddressVoid ptr(mVU->regs->Mem);
xAddressVoid ptr(mVU->regs().Mem);
if (_It_) {
mVUallocVIa(mVU, gprT1, _It_);
xMOV(gprT2, gprT1);
@ -1069,7 +1069,7 @@ mVUop(mVU_WAITQ) {
mVUop(mVU_XTOP) {
pass1 { if (!_It_) { mVUlow.isNOP = 1; } analyzeVIreg2(_It_, mVUlow.VI_write, 1); }
pass2 {
xMOVZX(gprT1, ptr16[&mVU->regs->vifRegs->top]);
xMOVZX(gprT1, ptr16[&mVU->getVifRegs().top]);
mVUallocVIb(mVU, gprT1, _It_);
}
pass3 { mVUlog("XTOP vi%02d", _Ft_); }
@ -1078,7 +1078,7 @@ mVUop(mVU_XTOP) {
mVUop(mVU_XITOP) {
pass1 { if (!_It_) { mVUlow.isNOP = 1; } analyzeVIreg2(_It_, mVUlow.VI_write, 1); }
pass2 {
xMOVZX(gprT1, ptr16[&mVU->regs->vifRegs->itop]);
xMOVZX(gprT1, ptr16[&mVU->getVifRegs().itop]);
xAND(gprT1, isVU1 ? 0x3ff : 0xff);
mVUallocVIb(mVU, gprT1, _It_);
}
@ -1094,7 +1094,7 @@ extern bool SIGNAL_IMR_Pending;
void __fastcall mVU_XGKICK_(u32 addr) {
addr &= 0x3ff;
u8* data = microVU1.regs->Mem + (addr*16);
u8* data = vuRegs[1].Mem + (addr*16);
u32 diff = 0x400 - addr;
u32 size;
@ -1128,11 +1128,11 @@ void __fastcall mVU_XGKICK_(u32 addr) {
if (size > diff) {
//DevCon.Status("XGkick Wrap!");
memcpy_qwc(pDest, microVU1.regs->Mem + (addr*16), diff);
memcpy_qwc(pDest+(diff*16), microVU1.regs->Mem, size-diff);
memcpy_qwc(pDest, vuRegs[1].Mem + (addr*16), diff);
memcpy_qwc(pDest+(diff*16), vuRegs[1].Mem, size-diff);
}
else {
memcpy_qwc(pDest, microVU1.regs->Mem + (addr*16), size);
memcpy_qwc(pDest, vuRegs[1].Mem + (addr*16), size);
}
//if(!gifRegs->stat.P1Q) CPU_INT(28, 128);
gifRegs->stat.P1Q = true;

View File

@ -18,6 +18,8 @@
extern void _vu0WaitMicro();
extern void _vu0FinishMicro();
static VURegs& vu0Regs = vuRegs[0];
//------------------------------------------------------------------
// Macro VU - Helper Macros / Functions
//------------------------------------------------------------------
@ -34,9 +36,9 @@ void setupMacroOp(int mode, const char* opName) {
microVU0.code = cpuRegs.code;
memset(&microVU0.prog.IRinfo.info[0], 0, sizeof(microVU0.prog.IRinfo.info[0]));
iFlushCall(FLUSH_EVERYTHING);
microVU0.regAlloc->reset(microVU0.regs);
microVU0.regAlloc->reset();
if (mode & 0x01) { // Q-Reg will be Read
xMOVSSZX(xmmPQ, ptr32[&microVU0.regs->VI[REG_Q].UL]);
xMOVSSZX(xmmPQ, ptr32[&vu0Regs.VI[REG_Q].UL]);
}
if (mode & 0x08) { // Clip Instruction
microVU0.prog.IRinfo.info[0].cFlag.write = 0xff;
@ -49,16 +51,16 @@ void setupMacroOp(int mode, const char* opName) {
microVU0.prog.IRinfo.info[0].sFlag.lastWrite = 0;
microVU0.prog.IRinfo.info[0].mFlag.doFlag = 1;
microVU0.prog.IRinfo.info[0].mFlag.write = 0xff;
xMOV(gprF0, ptr32[&microVU0.regs->VI[REG_STATUS_FLAG].UL]);
xMOV(gprF0, ptr32[&vu0Regs.VI[REG_STATUS_FLAG].UL]);
}
}
void endMacroOp(int mode) {
if (mode & 0x02) { // Q-Reg was Written To
xMOVSS(ptr32[&microVU0.regs->VI[REG_Q].UL], xmmPQ);
xMOVSS(ptr32[&vu0Regs.VI[REG_Q].UL], xmmPQ);
}
if (mode & 0x10) { // Status/Mac Flags were Updated
xMOV(ptr32[&microVU0.regs->VI[REG_STATUS_FLAG].UL], gprF0);
xMOV(ptr32[&vu0Regs.VI[REG_STATUS_FLAG].UL], gprF0);
}
microVU0.regAlloc->flushAll();
microVU0.cop2 = 0;
@ -267,10 +269,10 @@ static void recCFC2() {
iFlushCall(FLUSH_EVERYTHING);
if (_Rd_ == REG_STATUS_FLAG) { // Normalize Status Flag
xMOV(gprF0, ptr32[&microVU0.regs->VI[REG_STATUS_FLAG].UL]);
xMOV(gprF0, ptr32[&vu0Regs.VI[REG_STATUS_FLAG].UL]);
mVUallocSFLAGc(eax, gprF0, 0);
}
else xMOV(eax, ptr32[&microVU0.regs->VI[_Rd_].UL]);
else xMOV(eax, ptr32[&vu0Regs.VI[_Rd_].UL]);
// FixMe: Should R-Reg have upper 9 bits 0?
xMOV(ptr32[&cpuRegs.GPR.r[_Rt_].UL[0]], eax);
@ -298,14 +300,14 @@ static void recCTC2() {
case REG_R:
xMOV(eax, ptr32[&cpuRegs.GPR.r[_Rt_].UL[0]]);
xOR (eax, 0x3f800000);
xMOV(ptr32[&microVU0.regs->VI[REG_R].UL], eax);
xMOV(ptr32[&vu0Regs.VI[REG_R].UL], eax);
break;
case REG_STATUS_FLAG:
if (_Rt_) { // Denormalizes flag into gprF1
mVUallocSFLAGd(&cpuRegs.GPR.r[_Rt_].UL[0], 0);
xMOV(ptr32[&microVU0.regs->VI[_Rd_].UL], gprF1);
xMOV(ptr32[&vu0Regs.VI[_Rd_].UL], gprF1);
}
else xMOV(ptr32[&microVU0.regs->VI[_Rd_].UL], 0);
else xMOV(ptr32[&vu0Regs.VI[_Rd_].UL], 0);
break;
case REG_CMSAR1: // Execute VU1 Micro SubRoutine
if (_Rt_) {
@ -316,7 +318,7 @@ static void recCTC2() {
break;
case REG_FBRST:
if (!_Rt_) {
xMOV(ptr32[&microVU0.regs->VI[REG_FBRST].UL], 0);
xMOV(ptr32[&vu0Regs.VI[REG_FBRST].UL], 0);
return;
}
else xMOV(eax, ptr32[&cpuRegs.GPR.r[_Rt_].UL[0]]);
@ -325,12 +327,12 @@ static void recCTC2() {
TEST_FBRST_RESET(vu1ResetRegs, 1);
xAND(eax, 0x0C0C);
xMOV(ptr32[&microVU0.regs->VI[REG_FBRST].UL], eax);
xMOV(ptr32[&vu0Regs.VI[REG_FBRST].UL], eax);
break;
default:
// Executing vu0 block here fixes the intro of Ratchet and Clank
// sVU's COP2 has a comment that "Donald Duck" needs this too...
if (_Rd_) _eeMoveGPRtoM((uptr)&microVU0.regs->VI[_Rd_].UL, _Rt_);
if (_Rd_) _eeMoveGPRtoM((uptr)&vu0Regs.VI[_Rd_].UL, _Rt_);
xMOV(ecx, (uptr)CpuVU0);
xCALL(BaseVUmicroCPU::ExecuteBlockJIT);
break;
@ -347,7 +349,7 @@ static void recQMFC2() {
// FixMe: For some reason this line is needed or else games break:
_eeOnWriteReg(_Rt_, 0);
xMOVAPS(xmmT1, ptr128[&microVU0.regs->VF[_Rd_]]);
xMOVAPS(xmmT1, ptr128[&vu0Regs.VF[_Rd_]]);
xMOVAPS(ptr128[&cpuRegs.GPR.r[_Rt_]], xmmT1);
}
@ -359,7 +361,7 @@ static void recQMTC2() {
iFlushCall(FLUSH_EVERYTHING);
xMOVAPS(xmmT1, ptr128[&cpuRegs.GPR.r[_Rt_]]);
xMOVAPS(ptr128[&microVU0.regs->VF[_Rd_]], xmmT1);
xMOVAPS(ptr128[&vu0Regs.VF[_Rd_]], xmmT1);
}
//------------------------------------------------------------------

View File

@ -205,7 +205,7 @@ typedef u32 (__fastcall *mVUCall)(void*, void*);
#define isEvilBlock (mVUpBlock->pState.blockType == 2)
#define isBadOrEvil (mVUlow.badBranch || mVUlow.evilBranch)
#define xPC ((iPC / 2) * 8)
#define curI ((u32*)mVU->regs->Micro)[iPC] //mVUcurProg.data[iPC]
#define curI ((u32*)mVU->regs().Micro)[iPC] //mVUcurProg.data[iPC]
#define setCode() { mVU->code = curI; }
#if 0
@ -222,7 +222,7 @@ typedef u32 (__fastcall *mVUCall)(void*, void*);
#define bSaveAddr (((xPC + 16) & (mVU->microMemSize-8)) / 8)
#define shufflePQ (((mVU->p) ? 0xb0 : 0xe0) | ((mVU->q) ? 0x01 : 0x04))
#define cmpOffset(x) ((u8*)&(((u8*)x)[it[0].start]))
#define Rmem &mVU->regs->VI[REG_R].UL
#define Rmem &mVU->regs().VI[REG_R].UL
#define aWrap(x, m) ((x > m) ? 0 : x)
#define shuffleSS(x) ((x==1)?(0x27):((x==2)?(0xc6):((x==4)?(0xe1):(0xe4))))
#define clampE CHECK_VU_EXTRA_OVERFLOW
@ -325,4 +325,3 @@ typedef u32 (__fastcall *mVUCall)(void*, void*);
extern void mVUmergeRegs(const xmm& dest, const xmm& src, int xyzw, bool modXYZW=false);
extern void mVUsaveReg(const xmm& reg, xAddressVoid ptr, int xyzw, bool modXYZW);
extern void mVUloadReg(const xmm& reg, xAddressVoid ptr, int xyzw);
extern void mVUloadIreg(const xmm& reg, int xyzw, VURegs* vuRegs);

View File

@ -1948,7 +1948,7 @@ void recVUMI_XITOP( VURegs *VU, int info )
if (_It_ == 0) return;
//Console.WriteLn("recVUMI_XITOP");
itreg = ALLOCVI(_It_, MODE_WRITE);
MOVZX32M16toR( itreg, (uptr)&VU->vifRegs->itop );
MOVZX32M16toR( itreg, (uptr)&VU->GetVifRegs().itop );
}
//------------------------------------------------------------------
@ -1962,7 +1962,7 @@ void recVUMI_XTOP( VURegs *VU, int info )
if ( _It_ == 0 ) return;
//Console.WriteLn("recVUMI_XTOP");
itreg = ALLOCVI(_It_, MODE_WRITE);
MOVZX32M16toR( itreg, (uptr)&VU->vifRegs->top );
MOVZX32M16toR( itreg, (uptr)&VU->GetVifRegs().top );
}
//------------------------------------------------------------------

View File

@ -19,9 +19,6 @@
extern u32 vudump;
#define VU0_MEMSIZE 0x1000
#define VU1_MEMSIZE 0x4000
u32 GetVIAddr(VURegs * VU, int reg, int read, int info); // returns the correct VI addr
void recUpdateFlags(VURegs * VU, int reg, int info);

View File

@ -2750,7 +2750,7 @@ static void SuperVURecompile()
pxAssert(pchild->blocks.size() == 0);
AND32ItoM((uptr)&VU0.VI[ REG_VPU_STAT ].UL, s_vu ? ~0x100 : ~0x001); // E flag
AND32ItoM((uptr)&VU->vifRegs->stat, ~VIF1_STAT_VEW);
AND32ItoM((uptr)&VU->GetVifRegs().stat, ~VIF1_STAT_VEW);
MOV32ItoM((uptr)&VU->VI[REG_TPC], pchild->endpc);
JMP32((uptr)SuperVUEndProgram - ((uptr)x86Ptr + 5));
@ -3023,7 +3023,7 @@ void VuBaseBlock::Recompile()
_freeXMMregs();
_freeX86regs();
AND32ItoM((uptr)&VU0.VI[ REG_VPU_STAT ].UL, s_vu ? ~0x100 : ~0x001); // E flag
AND32ItoM((uptr)&VU->vifRegs->stat, ~VIF1_STAT_VEW);
AND32ItoM((uptr)&VU->GetVifRegs().stat, ~VIF1_STAT_VEW);
if (!branch) MOV32ItoM((uptr)&VU->VI[REG_TPC], endpc);
@ -4680,12 +4680,8 @@ void recSuperVU1::Execute(u32 cycles)
// [TODO] Debugging pre- and post- hooks?
if (VU1.VI[REG_TPC].UL >= VU1.maxmicro) {
Console.Error("VU1 memory overflow!!: %x", VU1.VI[REG_TPC].UL);
}
do { // while loop needed since not always will return finished
SuperVUExecuteProgram(VU1.VI[REG_TPC].UL & 0x3fff, 1);
SuperVUExecuteProgram(VU1.VI[REG_TPC].UL & VU1_PROGMASK, 1);
} while( VU0.VI[REG_VPU_STAT].UL&0x100 );
}