mirror of https://github.com/PCSX2/pcsx2.git
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:
parent
28dc7cfe69
commit
bda94b16cd
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -277,7 +277,7 @@ struct GIFregisters
|
|||
u32 padding9[3];
|
||||
};
|
||||
|
||||
#define gifRegs ((GIFregisters*)(eeMem->HW+0x3000))
|
||||
#define gifRegs ((GIFregisters*)(eeHw+0x3000))
|
||||
|
||||
extern tGSTransferStatus GSTransferStatus;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
10
pcsx2/Hw.h
10
pcsx2/Hw.h
|
@ -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);
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -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!
|
||||
|
|
|
@ -245,7 +245,7 @@ struct IPUregisters {
|
|||
u32 dummy3[2];
|
||||
};
|
||||
|
||||
#define ipuRegs ((IPUregisters*)(&eeMem->HW[0x2000]))
|
||||
#define ipuRegs ((IPUregisters*)(&eeHw[0x2000]))
|
||||
|
||||
struct tIPU_cmd
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
70
pcsx2/VU.h
70
pcsx2/VU.h
|
@ -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);
|
||||
|
||||
|
|
|
@ -44,8 +44,6 @@
|
|||
|
||||
using namespace R5900;
|
||||
|
||||
__aligned16 VURegs VU0;
|
||||
|
||||
void COP2_BC2() { Int_COP2BC2PrintTable[_Rt_]();}
|
||||
void COP2_SPECIAL() { Int_COP2SPECIAL1PrintTable[_Funct_]();}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
_vu0Exec(VU);
|
||||
}
|
||||
VU0.VI[REG_TPC].UL &= VU0_PROGMASK;
|
||||
_vu0Exec(VU);
|
||||
VU->cycle++;
|
||||
|
||||
if (VU->VI[0].UL != 0) DbgCon.Error("VI[0] != 0!!!!\n");
|
||||
|
|
|
@ -24,8 +24,6 @@
|
|||
|
||||
#include "VUmicro.h"
|
||||
|
||||
VURegs* g_pVU1;
|
||||
|
||||
#ifdef PCSX2_DEBUG
|
||||
u32 vudump = 0;
|
||||
#endif
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -639,6 +639,10 @@
|
|||
RelativePath="..\..\x86\microVU_IR.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\x86\microVU_IR.inl"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\x86\microVU_Log.inl"
|
||||
>
|
||||
|
|
|
@ -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);
|
||||
mVUemitSearch();
|
||||
}
|
||||
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(µVU0);
|
||||
microVU0.close();
|
||||
}
|
||||
}
|
||||
void recMicroVU1::Shutdown() throw() {
|
||||
if (m_AllocCount > 0) {
|
||||
m_AllocCount--;
|
||||
if (AtomicExchange(mvu1_allocated, 0) == 1)
|
||||
mVUclose(µVU1);
|
||||
microVU1.close();
|
||||
}
|
||||
}
|
||||
|
||||
void recMicroVU0::Reset() {
|
||||
if(!pxAssertDev(m_AllocCount, "MicroVU0 CPU Provider has not been allocated prior to reset!")) return;
|
||||
mVUreset(µVU0, &VU0);
|
||||
microVU0.reset();
|
||||
}
|
||||
void recMicroVU1::Reset() {
|
||||
if(!pxAssertDev(m_AllocCount, "MicroVU1 CPU Provider has not been allocated prior to reset!")) return;
|
||||
mVUreset(µVU1, &VU1);
|
||||
microVU1.reset();
|
||||
}
|
||||
|
||||
void recMicroVU0::Execute(u32 cycles) {
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)); }
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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); }
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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() { }
|
||||
|
||||
void reset(VURegs* vuRegsPtr) {
|
||||
vuRegs = vuRegsPtr;
|
||||
microRegAlloc(microVU* _mVU);
|
||||
|
||||
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);
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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(µVU0.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[µVU0.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[µVU0.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[µVU0.regs->VI[REG_Q].UL], xmmPQ);
|
||||
xMOVSS(ptr32[&vu0Regs.VI[REG_Q].UL], xmmPQ);
|
||||
}
|
||||
if (mode & 0x10) { // Status/Mac Flags were Updated
|
||||
xMOV(ptr32[µVU0.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[µVU0.regs->VI[REG_STATUS_FLAG].UL]);
|
||||
xMOV(gprF0, ptr32[&vu0Regs.VI[REG_STATUS_FLAG].UL]);
|
||||
mVUallocSFLAGc(eax, gprF0, 0);
|
||||
}
|
||||
else xMOV(eax, ptr32[µVU0.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[µVU0.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[µVU0.regs->VI[_Rd_].UL], gprF1);
|
||||
xMOV(ptr32[&vu0Regs.VI[_Rd_].UL], gprF1);
|
||||
}
|
||||
else xMOV(ptr32[µVU0.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[µVU0.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[µVU0.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)µVU0.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[µVU0.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[µVU0.regs->VF[_Rd_]], xmmT1);
|
||||
xMOVAPS(ptr128[&vu0Regs.VF[_Rd_]], xmmT1);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
|
|
|
@ -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);
|
|
@ -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 );
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue