mirror of https://github.com/PCSX2/pcsx2.git
Added more info to GS window. Added const qualifiers to VIF and DMAC hw register structs/unions.
git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2529 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
c109fbeaae
commit
a9165dfbf6
102
pcsx2/Dmac.h
102
pcsx2/Dmac.h
|
@ -97,9 +97,9 @@ union tDMA_TAG {
|
|||
u32 _u32;
|
||||
|
||||
tDMA_TAG(u32 val) { _u32 = val; }
|
||||
u16 upper() { return (_u32 >> 16); }
|
||||
u16 lower() { return (u16)_u32; }
|
||||
wxString tag_to_str()
|
||||
u16 upper() const { return (_u32 >> 16); }
|
||||
u16 lower() const { return (u16)_u32; }
|
||||
wxString tag_to_str() const
|
||||
{
|
||||
switch(ID)
|
||||
{
|
||||
|
@ -134,14 +134,14 @@ union tDMA_CHCR {
|
|||
|
||||
tDMA_CHCR( u32 val) { _u32 = val; }
|
||||
|
||||
bool test(u32 flags) { return !!(_u32 & flags); }
|
||||
bool test(u32 flags) const { return !!(_u32 & flags); }
|
||||
void set(u32 value) { _u32 = value; }
|
||||
void set_flags(u32 flags) { _u32 |= flags; }
|
||||
void clear_flags(u32 flags) { _u32 &= ~flags; }
|
||||
void reset() { _u32 = 0; }
|
||||
u16 upper() { return (_u32 >> 16); }
|
||||
u16 lower() { return (u16)_u32; }
|
||||
wxString desc() { return wxsFormat(L"Chcr: 0x%x", _u32); }
|
||||
u16 upper() const { return (_u32 >> 16); }
|
||||
u16 lower() const { return (u16)_u32; }
|
||||
wxString desc() const { return wxsFormat(L"Chcr: 0x%x", _u32); }
|
||||
};
|
||||
|
||||
#define CHCR(value) ((tDMA_CHCR)(value))
|
||||
|
@ -156,7 +156,7 @@ union tDMA_SADR {
|
|||
tDMA_SADR(u32 val) { _u32 = val; }
|
||||
|
||||
void reset() { _u32 = 0; }
|
||||
wxString desc() { return wxsFormat(L"Sadr: 0x%x", _u32); }
|
||||
wxString desc() const { return wxsFormat(L"Sadr: 0x%x", _u32); }
|
||||
};
|
||||
|
||||
union tDMA_MADR {
|
||||
|
@ -169,7 +169,7 @@ union tDMA_MADR {
|
|||
tDMA_MADR(u32 val) { _u32 = val; }
|
||||
|
||||
void reset() { _u32 = 0; }
|
||||
wxString desc() { return wxsFormat(L"Madr: 0x%x", _u32); }
|
||||
wxString desc() const { return wxsFormat(L"Madr: 0x%x", _u32); }
|
||||
};
|
||||
|
||||
union tDMA_TADR {
|
||||
|
@ -182,7 +182,7 @@ union tDMA_TADR {
|
|||
tDMA_TADR(u32 val) { _u32 = val; }
|
||||
|
||||
void reset() { _u32 = 0; }
|
||||
wxString desc() { return wxsFormat(L"Tadr: 0x%x", _u32); }
|
||||
wxString desc() const { return wxsFormat(L"Tadr: 0x%x", _u32); }
|
||||
};
|
||||
|
||||
union tDMA_ASR { // The Address Stack Register
|
||||
|
@ -195,7 +195,7 @@ union tDMA_ASR { // The Address Stack Register
|
|||
tDMA_ASR(u32 val) { _u32 = val; }
|
||||
|
||||
void reset() { _u32 = 0; }
|
||||
wxString desc() { return wxsFormat(L"Asr: 0x%x", _u32); }
|
||||
wxString desc() const { return wxsFormat(L"Asr: 0x%x", _u32); }
|
||||
};
|
||||
|
||||
union tDMA_QWC {
|
||||
|
@ -208,7 +208,7 @@ union tDMA_QWC {
|
|||
tDMA_QWC(u32 val) { _u32 = val; }
|
||||
|
||||
void reset() { _u32 = 0; }
|
||||
wxString desc() { return wxsFormat(L"QWC: 0x%x", _u32); }
|
||||
wxString desc() const { return wxsFormat(L"QWC: 0x%x", _u32); }
|
||||
};
|
||||
static __forceinline void setDmacStat(u32 num);
|
||||
static __forceinline tDMA_TAG *dmaGetAddr(u32 addr);
|
||||
|
@ -282,17 +282,17 @@ struct DMACh {
|
|||
return tag;
|
||||
}
|
||||
|
||||
tDMA_TAG dma_tag()
|
||||
tDMA_TAG dma_tag() const
|
||||
{
|
||||
return DMA_TAG(chcr._u32);
|
||||
}
|
||||
|
||||
wxString cmq_to_str()
|
||||
wxString cmq_to_str() const
|
||||
{
|
||||
return wxsFormat(L"chcr = %lx, madr = %lx, qwc = %lx", chcr._u32, madr, qwc);
|
||||
}
|
||||
|
||||
wxString cmqt_to_str()
|
||||
wxString cmqt_to_str() const
|
||||
{
|
||||
return wxsFormat(L"chcr = %lx, madr = %lx, qwc = %lx, tadr = %1x", chcr._u32, madr, qwc, tadr);
|
||||
}
|
||||
|
@ -385,7 +385,7 @@ union tDMAC_QUEUE
|
|||
|
||||
tDMAC_QUEUE(u16 val) { _u16 = val; }
|
||||
void reset() { _u16 = 0; }
|
||||
bool empty() { return (_u16 == 0); }
|
||||
bool empty() const { return (_u16 == 0); }
|
||||
};
|
||||
|
||||
static __forceinline const wxChar* ChcrName(u32 addr)
|
||||
|
@ -420,11 +420,11 @@ union tDMAC_CTRL {
|
|||
|
||||
tDMAC_CTRL(u32 val) { _u32 = val; }
|
||||
|
||||
bool test(u32 flags) { return !!(_u32 & flags); }
|
||||
bool test(u32 flags) const { return !!(_u32 & flags); }
|
||||
void set_flags(u32 flags) { _u32 |= flags; }
|
||||
void clear_flags(u32 flags) { _u32 &= ~flags; }
|
||||
void reset() { _u32 = 0; }
|
||||
wxString desc() { return wxsFormat(L"Ctrl: 0x%x", _u32); }
|
||||
wxString desc() const { return wxsFormat(L"Ctrl: 0x%x", _u32); }
|
||||
};
|
||||
|
||||
union tDMAC_STAT {
|
||||
|
@ -444,11 +444,11 @@ union tDMAC_STAT {
|
|||
|
||||
tDMAC_STAT(u32 val) { _u32 = val; }
|
||||
|
||||
bool test(u32 flags) { return !!(_u32 & flags); }
|
||||
bool test(u32 flags) const { return !!(_u32 & flags); }
|
||||
void set_flags(u32 flags) { _u32 |= flags; }
|
||||
void clear_flags(u32 flags) { _u32 &= ~flags; }
|
||||
void reset() { _u32 = 0; }
|
||||
wxString desc() { return wxsFormat(L"Stat: 0x%x", _u32); }
|
||||
wxString desc() const { return wxsFormat(L"Stat: 0x%x", _u32); }
|
||||
};
|
||||
|
||||
union tDMAC_PCR {
|
||||
|
@ -463,11 +463,11 @@ union tDMAC_PCR {
|
|||
|
||||
tDMAC_PCR(u32 val) { _u32 = val; }
|
||||
|
||||
bool test(u32 flags) { return !!(_u32 & flags); }
|
||||
bool test(u32 flags) const { return !!(_u32 & flags); }
|
||||
void set_flags(u32 flags) { _u32 |= flags; }
|
||||
void clear_flags(u32 flags) { _u32 &= ~flags; }
|
||||
void reset() { _u32 = 0; }
|
||||
wxString desc() { return wxsFormat(L"Pcr: 0x%x", _u32); }
|
||||
wxString desc() const { return wxsFormat(L"Pcr: 0x%x", _u32); }
|
||||
};
|
||||
|
||||
union tDMAC_SQWC {
|
||||
|
@ -481,11 +481,11 @@ union tDMAC_SQWC {
|
|||
|
||||
tDMAC_SQWC(u32 val) { _u32 = val; }
|
||||
|
||||
bool test(u32 flags) { return !!(_u32 & flags); }
|
||||
bool test(u32 flags) const { return !!(_u32 & flags); }
|
||||
void set_flags(u32 flags) { _u32 |= flags; }
|
||||
void clear_flags(u32 flags) { _u32 &= ~flags; }
|
||||
void reset() { _u32 = 0; }
|
||||
wxString desc() { return wxsFormat(L"Sqwc: 0x%x", _u32); }
|
||||
wxString desc() const { return wxsFormat(L"Sqwc: 0x%x", _u32); }
|
||||
};
|
||||
|
||||
union tDMAC_RBSR {
|
||||
|
@ -498,7 +498,7 @@ union tDMAC_RBSR {
|
|||
tDMAC_RBSR(u32 val) { _u32 = val; }
|
||||
|
||||
void reset() { _u32 = 0; }
|
||||
wxString desc() { return wxsFormat(L"Rbsr: 0x%x", _u32); }
|
||||
wxString desc() const { return wxsFormat(L"Rbsr: 0x%x", _u32); }
|
||||
};
|
||||
|
||||
union tDMAC_RBOR {
|
||||
|
@ -511,7 +511,7 @@ union tDMAC_RBOR {
|
|||
tDMAC_RBOR(u32 val) { _u32 = val; }
|
||||
|
||||
void reset() { _u32 = 0; }
|
||||
wxString desc() { return wxsFormat(L"Rbor: 0x%x", _u32); }
|
||||
wxString desc() const { return wxsFormat(L"Rbor: 0x%x", _u32); }
|
||||
};
|
||||
|
||||
union tDMAC_STADR {
|
||||
|
@ -524,7 +524,7 @@ union tDMAC_STADR {
|
|||
tDMAC_STADR(u32 val) { _u32 = val; }
|
||||
|
||||
void reset() { _u32 = 0; }
|
||||
wxString desc() { return wxsFormat(L"Stadr: 0x%x", _u32); }
|
||||
wxString desc() const { return wxsFormat(L"Stadr: 0x%x", _u32); }
|
||||
};
|
||||
|
||||
|
||||
|
@ -556,11 +556,11 @@ union tINTC_STAT {
|
|||
|
||||
tINTC_STAT(u32 val) { _u32 = val; }
|
||||
|
||||
bool test(u32 flags) { return !!(_u32 & flags); }
|
||||
bool test(u32 flags) const { return !!(_u32 & flags); }
|
||||
void set_flags(u32 flags) { _u32 |= flags; }
|
||||
void clear_flags(u32 flags) { _u32 &= ~flags; }
|
||||
void reset() { _u32 = 0; }
|
||||
wxString desc() { return wxsFormat(L"Stat: 0x%x", _u32); }
|
||||
wxString desc() const { return wxsFormat(L"Stat: 0x%x", _u32); }
|
||||
};
|
||||
|
||||
union tINTC_MASK {
|
||||
|
@ -572,11 +572,11 @@ union tINTC_MASK {
|
|||
|
||||
tINTC_MASK(u32 val) { _u32 = val; }
|
||||
|
||||
bool test(u32 flags) { return !!(_u32 & flags); }
|
||||
bool test(u32 flags) const { return !!(_u32 & flags); }
|
||||
void set_flags(u32 flags) { _u32 |= flags; }
|
||||
void clear_flags(u32 flags) { _u32 &= ~flags; }
|
||||
void reset() { _u32 = 0; }
|
||||
wxString desc() { return wxsFormat(L"Mask: 0x%x", _u32); }
|
||||
wxString desc() const { return wxsFormat(L"Mask: 0x%x", _u32); }
|
||||
};
|
||||
|
||||
struct INTCregisters
|
||||
|
@ -642,43 +642,3 @@ extern void intcInterrupt();
|
|||
extern void dmacInterrupt();
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// Everything after this comment is obsolete, and can be ignored.
|
||||
#ifdef PCSX2_VIRTUAL_MEM
|
||||
|
||||
#define dmaGetAddrBase(addr) (((addr) & 0x80000000) ? (void*)&PS2MEM_SCRATCH[(addr) & 0x3ff0] : (void*)(PS2MEM_BASE+TRANSFORM_ADDR(addr)))
|
||||
|
||||
#ifdef _WIN32
|
||||
extern PSMEMORYMAP* memLUT;
|
||||
#endif
|
||||
|
||||
// VM-version of dmaGetAddr -- Left in for references purposes for now (air)
|
||||
static __forceinline u8* dmaGetAddr(u32 mem)
|
||||
{
|
||||
u8* p, *pbase;
|
||||
mem &= ~0xf;
|
||||
|
||||
if( (mem&0xffff0000) == 0x50000000 ) {// reserved scratch pad mem
|
||||
Console.WriteLn("dmaGetAddr: reserved scratch pad mem");
|
||||
return NULL;//(u8*)&PS2MEM_SCRATCH[(mem) & 0x3ff0];
|
||||
}
|
||||
|
||||
p = (u8*)dmaGetAddrBase(mem);
|
||||
|
||||
#ifdef _WIN32
|
||||
// do manual LUT since IPU/SPR seems to use addrs 0x3000xxxx quite often
|
||||
// linux doesn't suffer from this because it has better vm support
|
||||
if( memLUT[ (p-PS2MEM_BASE)>>12 ].aPFNs == NULL ) {
|
||||
Console.WriteLn("dmaGetAddr: memLUT PFN warning");
|
||||
return NULL;//p;
|
||||
}
|
||||
|
||||
pbase = (u8*)memLUT[ (p-PS2MEM_BASE)>>12 ].aVFNs[0];
|
||||
if( pbase != NULL ) p = pbase + ((u32)p&0xfff);
|
||||
#endif
|
||||
|
||||
return p;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
17
pcsx2/Hw.h
17
pcsx2/Hw.h
|
@ -246,6 +246,23 @@ enum GSRegisterAddresses
|
|||
GS_SIGLBLID = 0x12001080
|
||||
};
|
||||
|
||||
// bleh, I'm graindead -- air
|
||||
union tGS_SMODE2
|
||||
{
|
||||
struct
|
||||
{
|
||||
u32 INT:1;
|
||||
u32 FFMD:1;
|
||||
u32 DPMS:2;
|
||||
u32 _PAD2:28;
|
||||
u32 _PAD3:32;
|
||||
};
|
||||
|
||||
u64 _u64;
|
||||
|
||||
bool IsInterlaced() const { return INT; }
|
||||
};
|
||||
|
||||
void hwReset();
|
||||
|
||||
// hw read functions
|
||||
|
|
|
@ -83,7 +83,7 @@ union tIPU_CTRL {
|
|||
// minus the reserved bits. (18-19; 27-29) [0x47f30000]
|
||||
void write(u32 value) { _u32 = (value & 0x47f30000) | (_u32 & 0x8000ffff); }
|
||||
|
||||
bool test(u32 flags) { return !!(_u32 & flags); }
|
||||
bool test(u32 flags) const { return !!(_u32 & flags); }
|
||||
void set_flags(u32 flags) { _u32 |= flags; }
|
||||
void clear_flags(u32 flags) { _u32 &= ~flags; }
|
||||
void reset() { _u32 = 0; }
|
||||
|
@ -119,7 +119,7 @@ union tIPU_CMD_IDEC
|
|||
|
||||
tIPU_CMD_IDEC( u32 val ) { _u32 = val; }
|
||||
|
||||
bool test(u32 flags) { return !!(_u32 & flags); }
|
||||
bool test(u32 flags) const { return !!(_u32 & flags); }
|
||||
void set_flags(u32 flags) { _u32 |= flags; }
|
||||
void clear_flags(u32 flags) { _u32 &= ~flags; }
|
||||
void reset() { _u32 = 0; }
|
||||
|
@ -142,7 +142,7 @@ union tIPU_CMD_BDEC
|
|||
|
||||
tIPU_CMD_BDEC( u32 val ) { _u32 = val; }
|
||||
|
||||
bool test(u32 flags) { return !!(_u32 & flags); }
|
||||
bool test(u32 flags) const { return !!(_u32 & flags); }
|
||||
void set_flags(u32 flags) { _u32 |= flags; }
|
||||
void clear_flags(u32 flags) { _u32 &= ~flags; }
|
||||
void reset() { _u32 = 0; }
|
||||
|
@ -162,7 +162,7 @@ union tIPU_CMD_CSC
|
|||
|
||||
tIPU_CMD_CSC( u32 val ){ _u32 = val; }
|
||||
|
||||
bool test(u32 flags) { return !!(_u32 & flags); }
|
||||
bool test(u32 flags) const { return !!(_u32 & flags); }
|
||||
void set_flags(u32 flags) { _u32 |= flags; }
|
||||
void clear_flags(u32 flags) { _u32 &= ~flags; }
|
||||
void reset() { _u32 = 0; }
|
||||
|
@ -186,7 +186,7 @@ union tIPU_DMA
|
|||
|
||||
tIPU_DMA( u32 val ){ _u32 = val; }
|
||||
|
||||
bool test(u32 flags) { return !!(_u32 & flags); }
|
||||
bool test(u32 flags) const { return !!(_u32 & flags); }
|
||||
void set_flags(u32 flags) { _u32 |= flags; }
|
||||
void clear_flags(u32 flags) { _u32 &= ~flags; }
|
||||
void reset() { _u32 = 0; }
|
||||
|
@ -258,11 +258,11 @@ extern u8 __fastcall getBits8(u8 *address, u32 advance);
|
|||
extern int __fastcall getBits(u8 *address, u32 size, u32 advance);
|
||||
|
||||
// returns number of qw read
|
||||
int FIFOfrom_write(const u32 * value, int size);
|
||||
void FIFOfrom_read(void *value,int size);
|
||||
int FIFOto_read(void *value);
|
||||
int FIFOto_write(u32* pMem, int size);
|
||||
void FIFOto_clear();
|
||||
void FIFOfrom_clear();
|
||||
extern int FIFOfrom_write(const u32 * value, int size);
|
||||
extern void FIFOfrom_read(void *value,int size);
|
||||
extern int FIFOto_read(void *value);
|
||||
extern int FIFOto_write(u32* pMem, int size);
|
||||
extern void FIFOto_clear();
|
||||
extern void FIFOfrom_clear();
|
||||
|
||||
#endif
|
||||
|
|
30
pcsx2/Vif.h
30
pcsx2/Vif.h
|
@ -104,11 +104,11 @@ union tVIF_STAT {
|
|||
u32 _u32;
|
||||
|
||||
tVIF_STAT(u32 val) { _u32 = val; }
|
||||
bool test(u32 flags) { return !!(_u32 & flags); }
|
||||
bool test(u32 flags) const { return !!(_u32 & flags); }
|
||||
void set_flags (u32 flags) { _u32 |= flags; }
|
||||
void clear_flags(u32 flags) { _u32 &= ~flags; }
|
||||
void reset() { _u32 = 0; }
|
||||
wxString desc() { return wxsFormat(L"Stat: 0x%x", _u32); }
|
||||
wxString desc() const { return wxsFormat(L"Stat: 0x%x", _u32); }
|
||||
};
|
||||
|
||||
#define VIF_STAT(value) ((tVIF_STAT)(value))
|
||||
|
@ -123,12 +123,12 @@ union tVIF_FBRST {
|
|||
};
|
||||
u32 _u32;
|
||||
|
||||
tVIF_FBRST(u32 val) { _u32 = val; }
|
||||
bool test (u32 flags) { return !!(_u32 & flags); }
|
||||
void set_flags (u32 flags) { _u32 |= flags; }
|
||||
void clear_flags(u32 flags) { _u32 &= ~flags; }
|
||||
void reset() { _u32 = 0; }
|
||||
wxString desc() { return wxsFormat(L"Fbrst: 0x%x", _u32); }
|
||||
tVIF_FBRST(u32 val) { _u32 = val; }
|
||||
bool test (u32 flags) const { return !!(_u32 & flags); }
|
||||
void set_flags (u32 flags) { _u32 |= flags; }
|
||||
void clear_flags(u32 flags) { _u32 &= ~flags; }
|
||||
void reset() { _u32 = 0; }
|
||||
wxString desc() const { return wxsFormat(L"Fbrst: 0x%x", _u32); }
|
||||
};
|
||||
|
||||
#define FBRST(value) ((tVIF_FBRST)(value))
|
||||
|
@ -142,13 +142,13 @@ union tVIF_ERR {
|
|||
};
|
||||
u32 _u32;
|
||||
|
||||
tVIF_ERR (u32 val) { _u32 = val; }
|
||||
void write(u32 val) { _u32 = val; }
|
||||
bool test (u32 flags) { return !!(_u32 & flags); }
|
||||
void set_flags (u32 flags) { _u32 |= flags; }
|
||||
void clear_flags(u32 flags) { _u32 &= ~flags; }
|
||||
void reset() { _u32 = 0; }
|
||||
wxString desc() { return wxsFormat(L"Err: 0x%x", _u32); }
|
||||
tVIF_ERR (u32 val) { _u32 = val; }
|
||||
void write(u32 val) { _u32 = val; }
|
||||
bool test (u32 flags) const { return !!(_u32 & flags); }
|
||||
void set_flags (u32 flags) { _u32 |= flags; }
|
||||
void clear_flags(u32 flags) { _u32 &= ~flags; }
|
||||
void reset() { _u32 = 0; }
|
||||
wxString desc() const { return wxsFormat(L"Err: 0x%x", _u32); }
|
||||
};
|
||||
|
||||
struct vifCycle
|
||||
|
|
|
@ -336,6 +336,7 @@ void GSFrame::OnUpdateTitle( wxTimerEvent& evt )
|
|||
char gsDest[128];
|
||||
GSgetTitleInfo( gsDest );
|
||||
|
||||
|
||||
const wxChar* limiterStr = L"None";
|
||||
|
||||
if( g_Conf->EmuOptions.GS.FrameLimitEnable )
|
||||
|
@ -352,11 +353,16 @@ void GSFrame::OnUpdateTitle( wxTimerEvent& evt )
|
|||
if( m_CpuUsage.IsImplemented() )
|
||||
{
|
||||
m_CpuUsage.UpdateStats();
|
||||
cpuUsage = wxsFormat( L" | EE: %d%% | GS: %d%% | UI: %d%%", m_CpuUsage.GetEEcorePct(), m_CpuUsage.GetGsPct(), m_CpuUsage.GetGuiPct() );
|
||||
cpuUsage = wxsFormat( L" | EE: %3d%% | GS: %3d%% | UI: %3d%%", m_CpuUsage.GetEEcorePct(), m_CpuUsage.GetGsPct(), m_CpuUsage.GetGuiPct() );
|
||||
}
|
||||
|
||||
const u64& smode2 = *(u64*)PS2GS_BASE(GS_SMODE2);
|
||||
|
||||
SetTitle( wxsFormat( L"%s | Limiter: %s | fps: %2.02f%s",
|
||||
fromUTF8(gsDest).c_str(), limiterStr, fps, cpuUsage.c_str() )
|
||||
SetTitle( wxsFormat( L"%s | %s (%s) | Limiter: %s | fps: %6.02f%s",
|
||||
fromUTF8(gsDest).c_str(),
|
||||
(smode2 & 1) ? L"Interlaced" : L"Progressive",
|
||||
(smode2 & 2) ? L"frame" : L"field",
|
||||
limiterStr, fps, cpuUsage.c_str() )
|
||||
);
|
||||
|
||||
//States_GetCurrentSlot()
|
||||
|
|
|
@ -1,267 +1,267 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2009 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/>.
|
||||
*/
|
||||
|
||||
// newVif Dynarec - Dynamically Recompiles Vif 'unpack' Packets
|
||||
// authors: cottonvibes(@gmail.com)
|
||||
// Jake.Stine (@gmail.com)
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "newVif_UnpackSSE.h"
|
||||
|
||||
static __aligned16 nVifBlock _vBlock = {0};
|
||||
static __pagealigned u8 nVifMemCmp[__pagesize];
|
||||
|
||||
void dVifInit(int idx) {
|
||||
nVif[idx].numBlocks = 0;
|
||||
nVif[idx].vifCache = new BlockBuffer(_1mb*4); // 4mb Rec Cache
|
||||
nVif[idx].vifBlocks = new HashBucket<_tParams>();
|
||||
nVif[idx].recPtr = nVif[idx].vifCache->getBlock();
|
||||
nVif[idx].recEnd = &nVif[idx].recPtr[nVif[idx].vifCache->getSize()-(_1mb/4)]; // .25mb Safe Zone
|
||||
}
|
||||
|
||||
void dVifClose(int idx) {
|
||||
nVif[idx].numBlocks = 0;
|
||||
safe_delete(nVif[idx].vifCache);
|
||||
safe_delete(nVif[idx].vifBlocks);
|
||||
}
|
||||
|
||||
VifUnpackSSE_Dynarec::VifUnpackSSE_Dynarec(const nVifStruct& vif_, const nVifBlock& vifBlock_)
|
||||
: v(vif_)
|
||||
, vB(vifBlock_)
|
||||
{
|
||||
isFill = (vB.cl < vB.wl);
|
||||
usn = (vB.upkType>>5) & 1;
|
||||
doMask = (vB.upkType>>4) & 1;
|
||||
doMode = vB.mode & 3;
|
||||
}
|
||||
|
||||
#define makeMergeMask(x) { \
|
||||
x = ((x&0x40)>>6) | ((x&0x10)>>3) | (x&4) | ((x&1)<<3); \
|
||||
}
|
||||
|
||||
_f void VifUnpackSSE_Dynarec::SetMasks(int cS) const {
|
||||
u32 m0 = vB.mask;
|
||||
u32 m1 = m0 & 0xaaaaaaaa;
|
||||
u32 m2 =(~m1>>1) & m0;
|
||||
u32 m3 = (m1>>1) & ~m0;
|
||||
u32* row = (v.idx) ? g_vifmask.Row1 : g_vifmask.Row0;
|
||||
u32* col = (v.idx) ? g_vifmask.Col1 : g_vifmask.Col0;
|
||||
if((m2&&doMask) || doMode) { xMOVAPS(xmmRow, ptr32[row]); }
|
||||
if (m3&&doMask) {
|
||||
xMOVAPS(xmmCol0, ptr32[col]);
|
||||
if ((cS>=2) && (m3&0x0000ff00)) xPSHUF.D(xmmCol1, xmmCol0, _v1);
|
||||
if ((cS>=3) && (m3&0x00ff0000)) xPSHUF.D(xmmCol2, xmmCol0, _v2);
|
||||
if ((cS>=4) && (m3&0xff000000)) xPSHUF.D(xmmCol3, xmmCol0, _v3);
|
||||
if ((cS>=1) && (m3&0x000000ff)) xPSHUF.D(xmmCol0, xmmCol0, _v0);
|
||||
}
|
||||
//if (doMask||doMode) loadRowCol((nVifStruct&)v);
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Dynarec::doMaskWrite(const xRegisterSSE& regX) const {
|
||||
pxAssumeDev(regX.Id <= 1, "Reg Overflow! XMM2 thru XMM6 are reserved for masking.");
|
||||
int t = regX.Id ? 0 : 1; // Get Temp Reg
|
||||
int cc = aMin(vCL, 3);
|
||||
u32 m0 = (vB.mask >> (cc * 8)) & 0xff;
|
||||
u32 m1 = m0 & 0xaa;
|
||||
u32 m2 =(~m1>>1) & m0;
|
||||
u32 m3 = (m1>>1) & ~m0;
|
||||
u32 m4 = (m1>>1) & m0;
|
||||
makeMergeMask(m2);
|
||||
makeMergeMask(m3);
|
||||
makeMergeMask(m4);
|
||||
if (doMask&&m4) { xMOVAPS(xmmTemp, ptr[dstIndirect]); } // Load Write Protect
|
||||
if (doMask&&m2) { mergeVectors(regX.Id, xmmRow.Id, t, m2); } // Merge Row
|
||||
if (doMask&&m3) { mergeVectors(regX.Id, xmmCol0.Id+cc, t, m3); } // Merge Col
|
||||
if (doMask&&m4) { mergeVectors(regX.Id, xmmTemp.Id, t, m4); } // Merge Write Protect
|
||||
if (doMode) {
|
||||
u32 m5 = (~m1>>1) & ~m0;
|
||||
if (!doMask) m5 = 0xf;
|
||||
else makeMergeMask(m5);
|
||||
if (m5 < 0xf) {
|
||||
xPXOR(xmmTemp, xmmTemp);
|
||||
mergeVectors(xmmTemp.Id, xmmRow.Id, t, m5);
|
||||
xPADD.D(regX, xmmTemp);
|
||||
if (doMode==2) mergeVectors(xmmRow.Id, regX.Id, t, m5);
|
||||
}
|
||||
else if (m5 == 0xf) {
|
||||
xPADD.D(regX, xmmRow);
|
||||
if (doMode==2) xMOVAPS(xmmRow, regX);
|
||||
}
|
||||
}
|
||||
xMOVAPS(ptr32[dstIndirect], regX);
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Dynarec::writeBackRow() const {
|
||||
u32* row = (v.idx) ? g_vifmask.Row1 : g_vifmask.Row0;
|
||||
xMOVAPS(ptr32[row], xmmRow);
|
||||
DevCon.WriteLn("nVif: writing back row reg! [doMode = 2]");
|
||||
// ToDo: Do we need to write back to vifregs.rX too!? :/
|
||||
}
|
||||
|
||||
static void ShiftDisplacementWindow( xAddressInfo& addr, const xRegister32& modReg )
|
||||
{
|
||||
// Shifts the displacement factor of a given indirect address, so that the address
|
||||
// remains in the optimal 0xf0 range (which allows for byte-form displacements when
|
||||
// generating instructions).
|
||||
|
||||
int addImm = 0;
|
||||
while( addr.Displacement >= 0x80 )
|
||||
{
|
||||
addImm += 0xf0;
|
||||
addr -= 0xf0;
|
||||
}
|
||||
if(addImm) xADD(modReg, addImm);
|
||||
}
|
||||
static bool UsesTwoRegs[] =
|
||||
{
|
||||
true, true, true, true,
|
||||
false, false, false, false,
|
||||
false, false, false, false,
|
||||
false, false, false, true,
|
||||
|
||||
};
|
||||
|
||||
void VifUnpackSSE_Dynarec::CompileRoutine() {
|
||||
const int upkNum = v.vif->cmd & 0xf;
|
||||
const u8& vift = nVifT[upkNum];
|
||||
const int cycleSize = isFill ? vB.cl : vB.wl;
|
||||
const int blockSize = isFill ? vB.wl : vB.cl;
|
||||
const int skipSize = blockSize - cycleSize;
|
||||
|
||||
int vNum = v.vifRegs->num;
|
||||
vCL = v.vif->cl;
|
||||
doMode = upkNum == 0xf ? 0 : doMode;
|
||||
|
||||
SetMasks(cycleSize);
|
||||
|
||||
while (vNum) {
|
||||
|
||||
ShiftDisplacementWindow( srcIndirect, edx );
|
||||
ShiftDisplacementWindow( dstIndirect, ecx );
|
||||
|
||||
if (vCL < cycleSize) {
|
||||
xUnpack(upkNum);
|
||||
xMovDest();
|
||||
|
||||
dstIndirect += 16;
|
||||
srcIndirect += vift;
|
||||
|
||||
if( IsUnmaskedOp() ) {
|
||||
++destReg;
|
||||
++workReg;
|
||||
}
|
||||
|
||||
vNum--;
|
||||
if (++vCL == blockSize) vCL = 0;
|
||||
}
|
||||
else if (isFill) {
|
||||
DevCon.WriteLn("filling mode!");
|
||||
VifUnpackSSE_Dynarec fill( VifUnpackSSE_Dynarec::FillingWrite( *this ) );
|
||||
fill.xUnpack(upkNum);
|
||||
fill.xMovDest();
|
||||
|
||||
dstIndirect += 16;
|
||||
vNum--;
|
||||
if (++vCL == blockSize) vCL = 0;
|
||||
}
|
||||
else {
|
||||
dstIndirect += (16 * skipSize);
|
||||
vCL = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (doMode==2) writeBackRow();
|
||||
xMOV(ptr32[&v.vif->cl], vCL);
|
||||
xMOV(ptr32[&v.vifRegs->num], vNum);
|
||||
xRET();
|
||||
}
|
||||
|
||||
static _f u8* dVifsetVUptr(const nVifStruct& v, int cl, int wl, bool isFill) {
|
||||
u8* endPtr; // Check if we need to wrap around VU memory
|
||||
u8* ptr = (u8*)(v.VU->Mem + (v.vif->tag.addr & v.vuMemLimit));
|
||||
if (!isFill) { // Account for skip-cycles
|
||||
int skipSize = cl - wl;
|
||||
int blocks = _vBlock.num / wl;
|
||||
int skips = (blocks * skipSize + _vBlock.num) * 16;
|
||||
endPtr = ptr + skips;
|
||||
}
|
||||
else endPtr = ptr + (_vBlock.num * 16);
|
||||
if ( endPtr > v.vuMemEnd ) {
|
||||
DevCon.WriteLn("nVif - VU Mem Ptr Overflow; falling back to interpreter.");
|
||||
ptr = NULL; // Fall Back to Interpreters which have wrap-around logic
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static _f void dVifRecLimit(int idx) {
|
||||
if (nVif[idx].recPtr > nVif[idx].recEnd) {
|
||||
DevCon.WriteLn("nVif Rec - Out of Rec Cache! [%x > %x]", nVif[idx].recPtr, nVif[idx].recEnd);
|
||||
nVif[idx].vifBlocks->clear();
|
||||
nVif[idx].recPtr = nVif[idx].vifCache->getBlock();
|
||||
}
|
||||
}
|
||||
|
||||
_f void dVifUnpack(int idx, u8 *data, u32 size, bool isFill) {
|
||||
|
||||
const nVifStruct& v = nVif[idx];
|
||||
const u8 upkType = v.vif->cmd & 0x1f | ((!!v.vif->usn) << 5);
|
||||
const int doMask = v.vif->cmd & 0x10;
|
||||
const int cycle_cl = v.vifRegs->cycle.cl;
|
||||
const int cycle_wl = v.vifRegs->cycle.wl;
|
||||
const int cycleSize = isFill ? cycle_cl : cycle_wl;
|
||||
const int blockSize = isFill ? cycle_wl : cycle_cl;
|
||||
|
||||
if (v.vif->cl >= blockSize) v.vif->cl = 0;
|
||||
|
||||
_vBlock.upkType = upkType;
|
||||
_vBlock.num = (u8&)v.vifRegs->num;
|
||||
_vBlock.mode = (u8&)v.vifRegs->mode;
|
||||
_vBlock.scl = v.vif->cl;
|
||||
_vBlock.cl = cycle_cl;
|
||||
_vBlock.wl = cycle_wl;
|
||||
|
||||
// Zero out the mask parameter if it's unused -- games leave random junk
|
||||
// values here which cause false recblock cache misses.
|
||||
_vBlock.mask = doMask ? v.vifRegs->mask : 0;
|
||||
|
||||
if (nVifBlock* b = v.vifBlocks->find(&_vBlock)) {
|
||||
if (u8* dest = dVifsetVUptr(v, cycle_cl, cycle_wl, isFill)) {
|
||||
//DevCon.WriteLn("Running Recompiled Block!");
|
||||
((nVifrecCall)b->startPtr)((uptr)dest, (uptr)data);
|
||||
}
|
||||
else {
|
||||
//DevCon.WriteLn("Running Interpreter Block");
|
||||
_nVifUnpack(idx, data, size, isFill);
|
||||
}
|
||||
return;
|
||||
}
|
||||
//DevCon.WriteLn("nVif%d: Recompiled Block! [%d]", idx, nVif[idx].numBlocks++);
|
||||
//DevCon.WriteLn(L"[num=% 3d][upkType=0x%02x][scl=%d][cl=%d][wl=%d][mode=%d][m=%d][mask=%s]",
|
||||
// _vBlock.num, _vBlock.upkType, _vBlock.scl, _vBlock.cl, _vBlock.wl, _vBlock.mode,
|
||||
// doMask >> 4, doMask ? wxsFormat( L"0x%08x", _vBlock.mask ).c_str() : L"ignored"
|
||||
//);
|
||||
|
||||
xSetPtr(v.recPtr);
|
||||
_vBlock.startPtr = (uptr)xGetAlignedCallTarget();
|
||||
v.vifBlocks->add(_vBlock);
|
||||
VifUnpackSSE_Dynarec( v, _vBlock ).CompileRoutine();
|
||||
nVif[idx].recPtr = xGetPtr();
|
||||
|
||||
dVifRecLimit(idx);
|
||||
|
||||
// Run the block we just compiled. Various conditions may force us to still use
|
||||
// the interpreter unpacker though, so a recursive call is the safest way here...
|
||||
dVifUnpack(idx, data, size, isFill);
|
||||
}
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2009 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/>.
|
||||
*/
|
||||
|
||||
// newVif Dynarec - Dynamically Recompiles Vif 'unpack' Packets
|
||||
// authors: cottonvibes(@gmail.com)
|
||||
// Jake.Stine (@gmail.com)
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "newVif_UnpackSSE.h"
|
||||
|
||||
static __aligned16 nVifBlock _vBlock = {0};
|
||||
static __pagealigned u8 nVifMemCmp[__pagesize];
|
||||
|
||||
void dVifInit(int idx) {
|
||||
nVif[idx].numBlocks = 0;
|
||||
nVif[idx].vifCache = new BlockBuffer(_1mb*4); // 4mb Rec Cache
|
||||
nVif[idx].vifBlocks = new HashBucket<_tParams>();
|
||||
nVif[idx].recPtr = nVif[idx].vifCache->getBlock();
|
||||
nVif[idx].recEnd = &nVif[idx].recPtr[nVif[idx].vifCache->getSize()-(_1mb/4)]; // .25mb Safe Zone
|
||||
}
|
||||
|
||||
void dVifClose(int idx) {
|
||||
nVif[idx].numBlocks = 0;
|
||||
safe_delete(nVif[idx].vifCache);
|
||||
safe_delete(nVif[idx].vifBlocks);
|
||||
}
|
||||
|
||||
VifUnpackSSE_Dynarec::VifUnpackSSE_Dynarec(const nVifStruct& vif_, const nVifBlock& vifBlock_)
|
||||
: v(vif_)
|
||||
, vB(vifBlock_)
|
||||
{
|
||||
isFill = (vB.cl < vB.wl);
|
||||
usn = (vB.upkType>>5) & 1;
|
||||
doMask = (vB.upkType>>4) & 1;
|
||||
doMode = vB.mode & 3;
|
||||
}
|
||||
|
||||
#define makeMergeMask(x) { \
|
||||
x = ((x&0x40)>>6) | ((x&0x10)>>3) | (x&4) | ((x&1)<<3); \
|
||||
}
|
||||
|
||||
_f void VifUnpackSSE_Dynarec::SetMasks(int cS) const {
|
||||
u32 m0 = vB.mask;
|
||||
u32 m1 = m0 & 0xaaaaaaaa;
|
||||
u32 m2 =(~m1>>1) & m0;
|
||||
u32 m3 = (m1>>1) & ~m0;
|
||||
u32* row = (v.idx) ? g_vifmask.Row1 : g_vifmask.Row0;
|
||||
u32* col = (v.idx) ? g_vifmask.Col1 : g_vifmask.Col0;
|
||||
if((m2&&doMask) || doMode) { xMOVAPS(xmmRow, ptr32[row]); }
|
||||
if (m3&&doMask) {
|
||||
xMOVAPS(xmmCol0, ptr32[col]);
|
||||
if ((cS>=2) && (m3&0x0000ff00)) xPSHUF.D(xmmCol1, xmmCol0, _v1);
|
||||
if ((cS>=3) && (m3&0x00ff0000)) xPSHUF.D(xmmCol2, xmmCol0, _v2);
|
||||
if ((cS>=4) && (m3&0xff000000)) xPSHUF.D(xmmCol3, xmmCol0, _v3);
|
||||
if ((cS>=1) && (m3&0x000000ff)) xPSHUF.D(xmmCol0, xmmCol0, _v0);
|
||||
}
|
||||
//if (doMask||doMode) loadRowCol((nVifStruct&)v);
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Dynarec::doMaskWrite(const xRegisterSSE& regX) const {
|
||||
pxAssumeDev(regX.Id <= 1, "Reg Overflow! XMM2 thru XMM6 are reserved for masking.");
|
||||
int t = regX.Id ? 0 : 1; // Get Temp Reg
|
||||
int cc = aMin(vCL, 3);
|
||||
u32 m0 = (vB.mask >> (cc * 8)) & 0xff;
|
||||
u32 m1 = m0 & 0xaa;
|
||||
u32 m2 =(~m1>>1) & m0;
|
||||
u32 m3 = (m1>>1) & ~m0;
|
||||
u32 m4 = (m1>>1) & m0;
|
||||
makeMergeMask(m2);
|
||||
makeMergeMask(m3);
|
||||
makeMergeMask(m4);
|
||||
if (doMask&&m4) { xMOVAPS(xmmTemp, ptr[dstIndirect]); } // Load Write Protect
|
||||
if (doMask&&m2) { mergeVectors(regX.Id, xmmRow.Id, t, m2); } // Merge Row
|
||||
if (doMask&&m3) { mergeVectors(regX.Id, xmmCol0.Id+cc, t, m3); } // Merge Col
|
||||
if (doMask&&m4) { mergeVectors(regX.Id, xmmTemp.Id, t, m4); } // Merge Write Protect
|
||||
if (doMode) {
|
||||
u32 m5 = (~m1>>1) & ~m0;
|
||||
if (!doMask) m5 = 0xf;
|
||||
else makeMergeMask(m5);
|
||||
if (m5 < 0xf) {
|
||||
xPXOR(xmmTemp, xmmTemp);
|
||||
mergeVectors(xmmTemp.Id, xmmRow.Id, t, m5);
|
||||
xPADD.D(regX, xmmTemp);
|
||||
if (doMode==2) mergeVectors(xmmRow.Id, regX.Id, t, m5);
|
||||
}
|
||||
else if (m5 == 0xf) {
|
||||
xPADD.D(regX, xmmRow);
|
||||
if (doMode==2) xMOVAPS(xmmRow, regX);
|
||||
}
|
||||
}
|
||||
xMOVAPS(ptr32[dstIndirect], regX);
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Dynarec::writeBackRow() const {
|
||||
u32* row = (v.idx) ? g_vifmask.Row1 : g_vifmask.Row0;
|
||||
xMOVAPS(ptr32[row], xmmRow);
|
||||
DevCon.WriteLn("nVif: writing back row reg! [doMode = 2]");
|
||||
// ToDo: Do we need to write back to vifregs.rX too!? :/
|
||||
}
|
||||
|
||||
static void ShiftDisplacementWindow( xAddressInfo& addr, const xRegister32& modReg )
|
||||
{
|
||||
// Shifts the displacement factor of a given indirect address, so that the address
|
||||
// remains in the optimal 0xf0 range (which allows for byte-form displacements when
|
||||
// generating instructions).
|
||||
|
||||
int addImm = 0;
|
||||
while( addr.Displacement >= 0x80 )
|
||||
{
|
||||
addImm += 0xf0;
|
||||
addr -= 0xf0;
|
||||
}
|
||||
if(addImm) xADD(modReg, addImm);
|
||||
}
|
||||
static bool UsesTwoRegs[] =
|
||||
{
|
||||
true, true, true, true,
|
||||
false, false, false, false,
|
||||
false, false, false, false,
|
||||
false, false, false, true,
|
||||
|
||||
};
|
||||
|
||||
void VifUnpackSSE_Dynarec::CompileRoutine() {
|
||||
const int upkNum = v.vif->cmd & 0xf;
|
||||
const u8& vift = nVifT[upkNum];
|
||||
const int cycleSize = isFill ? vB.cl : vB.wl;
|
||||
const int blockSize = isFill ? vB.wl : vB.cl;
|
||||
const int skipSize = blockSize - cycleSize;
|
||||
|
||||
int vNum = v.vifRegs->num;
|
||||
vCL = v.vif->cl;
|
||||
doMode = upkNum == 0xf ? 0 : doMode;
|
||||
|
||||
SetMasks(cycleSize);
|
||||
|
||||
while (vNum) {
|
||||
|
||||
ShiftDisplacementWindow( srcIndirect, edx );
|
||||
ShiftDisplacementWindow( dstIndirect, ecx );
|
||||
|
||||
if (vCL < cycleSize) {
|
||||
xUnpack(upkNum);
|
||||
xMovDest();
|
||||
|
||||
dstIndirect += 16;
|
||||
srcIndirect += vift;
|
||||
|
||||
if( IsUnmaskedOp() ) {
|
||||
++destReg;
|
||||
++workReg;
|
||||
}
|
||||
|
||||
vNum--;
|
||||
if (++vCL == blockSize) vCL = 0;
|
||||
}
|
||||
else if (isFill) {
|
||||
DevCon.WriteLn("filling mode!");
|
||||
VifUnpackSSE_Dynarec fill( VifUnpackSSE_Dynarec::FillingWrite( *this ) );
|
||||
fill.xUnpack(upkNum);
|
||||
fill.xMovDest();
|
||||
|
||||
dstIndirect += 16;
|
||||
vNum--;
|
||||
if (++vCL == blockSize) vCL = 0;
|
||||
}
|
||||
else {
|
||||
dstIndirect += (16 * skipSize);
|
||||
vCL = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (doMode==2) writeBackRow();
|
||||
xMOV(ptr32[&v.vif->cl], vCL);
|
||||
xMOV(ptr32[&v.vifRegs->num], vNum);
|
||||
xRET();
|
||||
}
|
||||
|
||||
static _f u8* dVifsetVUptr(const nVifStruct& v, int cl, int wl, bool isFill) {
|
||||
u8* endPtr; // Check if we need to wrap around VU memory
|
||||
u8* ptr = (u8*)(v.VU->Mem + (v.vif->tag.addr & v.vuMemLimit));
|
||||
if (!isFill) { // Account for skip-cycles
|
||||
int skipSize = cl - wl;
|
||||
int blocks = _vBlock.num / wl;
|
||||
int skips = (blocks * skipSize + _vBlock.num) * 16;
|
||||
endPtr = ptr + skips;
|
||||
}
|
||||
else endPtr = ptr + (_vBlock.num * 16);
|
||||
if ( endPtr > v.vuMemEnd ) {
|
||||
DevCon.WriteLn("nVif - VU Mem Ptr Overflow; falling back to interpreter.");
|
||||
ptr = NULL; // Fall Back to Interpreters which have wrap-around logic
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static _f void dVifRecLimit(int idx) {
|
||||
if (nVif[idx].recPtr > nVif[idx].recEnd) {
|
||||
DevCon.WriteLn("nVif Rec - Out of Rec Cache! [%x > %x]", nVif[idx].recPtr, nVif[idx].recEnd);
|
||||
nVif[idx].vifBlocks->clear();
|
||||
nVif[idx].recPtr = nVif[idx].vifCache->getBlock();
|
||||
}
|
||||
}
|
||||
|
||||
_f void dVifUnpack(int idx, u8 *data, u32 size, bool isFill) {
|
||||
|
||||
const nVifStruct& v = nVif[idx];
|
||||
const u8 upkType = v.vif->cmd & 0x1f | ((!!v.vif->usn) << 5);
|
||||
const int doMask = v.vif->cmd & 0x10;
|
||||
const int cycle_cl = v.vifRegs->cycle.cl;
|
||||
const int cycle_wl = v.vifRegs->cycle.wl;
|
||||
const int cycleSize = isFill ? cycle_cl : cycle_wl;
|
||||
const int blockSize = isFill ? cycle_wl : cycle_cl;
|
||||
|
||||
if (v.vif->cl >= blockSize) v.vif->cl = 0;
|
||||
|
||||
_vBlock.upkType = upkType;
|
||||
_vBlock.num = (u8&)v.vifRegs->num;
|
||||
_vBlock.mode = (u8&)v.vifRegs->mode;
|
||||
_vBlock.scl = v.vif->cl;
|
||||
_vBlock.cl = cycle_cl;
|
||||
_vBlock.wl = cycle_wl;
|
||||
|
||||
// Zero out the mask parameter if it's unused -- games leave random junk
|
||||
// values here which cause false recblock cache misses.
|
||||
_vBlock.mask = doMask ? v.vifRegs->mask : 0;
|
||||
|
||||
if (nVifBlock* b = v.vifBlocks->find(&_vBlock)) {
|
||||
if (u8* dest = dVifsetVUptr(v, cycle_cl, cycle_wl, isFill)) {
|
||||
//DevCon.WriteLn("Running Recompiled Block!");
|
||||
((nVifrecCall)b->startPtr)((uptr)dest, (uptr)data);
|
||||
}
|
||||
else {
|
||||
//DevCon.WriteLn("Running Interpreter Block");
|
||||
_nVifUnpack(idx, data, size, isFill);
|
||||
}
|
||||
return;
|
||||
}
|
||||
//DevCon.WriteLn("nVif%d: Recompiled Block! [%d]", idx, nVif[idx].numBlocks++);
|
||||
//DevCon.WriteLn(L"[num=% 3d][upkType=0x%02x][scl=%d][cl=%d][wl=%d][mode=%d][m=%d][mask=%s]",
|
||||
// _vBlock.num, _vBlock.upkType, _vBlock.scl, _vBlock.cl, _vBlock.wl, _vBlock.mode,
|
||||
// doMask >> 4, doMask ? wxsFormat( L"0x%08x", _vBlock.mask ).c_str() : L"ignored"
|
||||
//);
|
||||
|
||||
xSetPtr(v.recPtr);
|
||||
_vBlock.startPtr = (uptr)xGetAlignedCallTarget();
|
||||
v.vifBlocks->add(_vBlock);
|
||||
VifUnpackSSE_Dynarec( v, _vBlock ).CompileRoutine();
|
||||
nVif[idx].recPtr = xGetPtr();
|
||||
|
||||
dVifRecLimit(idx);
|
||||
|
||||
// Run the block we just compiled. Various conditions may force us to still use
|
||||
// the interpreter unpacker though, so a recursive call is the safest way here...
|
||||
dVifUnpack(idx, data, size, isFill);
|
||||
}
|
||||
|
|
|
@ -1,310 +1,310 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2009 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/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "newVif_UnpackSSE.h"
|
||||
|
||||
#define xMOV8(regX, loc) xMOVSSZX(regX, loc)
|
||||
#define xMOV16(regX, loc) xMOVSSZX(regX, loc)
|
||||
#define xMOV32(regX, loc) xMOVSSZX(regX, loc)
|
||||
#define xMOV64(regX, loc) xMOVUPS(regX, loc)
|
||||
#define xMOV128(regX, loc) xMOVUPS(regX, loc)
|
||||
|
||||
static __pagealigned u8 nVifUpkExec[__pagesize*4];
|
||||
|
||||
// Merges xmm vectors without modifying source reg
|
||||
void mergeVectors(int dest, int src, int temp, int xyzw) {
|
||||
if (x86caps.hasStreamingSIMD4Extensions || (xyzw==15)
|
||||
|| (xyzw==12) || (xyzw==11) || (xyzw==8) || (xyzw==3)) {
|
||||
mVUmergeRegs(dest, src, xyzw);
|
||||
}
|
||||
else {
|
||||
SSE_MOVAPS_XMM_to_XMM(temp, src);
|
||||
mVUmergeRegs(dest, temp, xyzw);
|
||||
}
|
||||
}
|
||||
|
||||
// Loads Row/Col Data from vifRegs instead of g_vifmask
|
||||
// Useful for testing vifReg and g_vifmask inconsistency.
|
||||
void loadRowCol(nVifStruct& v) {
|
||||
xMOVAPS(xmm0, ptr32[&v.vifRegs->r0]);
|
||||
xMOVAPS(xmm1, ptr32[&v.vifRegs->r1]);
|
||||
xMOVAPS(xmm2, ptr32[&v.vifRegs->r2]);
|
||||
xMOVAPS(xmm6, ptr32[&v.vifRegs->r3]);
|
||||
xPSHUF.D(xmm0, xmm0, _v0);
|
||||
xPSHUF.D(xmm1, xmm1, _v0);
|
||||
xPSHUF.D(xmm2, xmm2, _v0);
|
||||
xPSHUF.D(xmm6, xmm6, _v0);
|
||||
mVUmergeRegs(XMM6, XMM0, 8);
|
||||
mVUmergeRegs(XMM6, XMM1, 4);
|
||||
mVUmergeRegs(XMM6, XMM2, 2);
|
||||
xMOVAPS(xmm2, ptr32[&v.vifRegs->c0]);
|
||||
xMOVAPS(xmm3, ptr32[&v.vifRegs->c1]);
|
||||
xMOVAPS(xmm4, ptr32[&v.vifRegs->c2]);
|
||||
xMOVAPS(xmm5, ptr32[&v.vifRegs->c3]);
|
||||
xPSHUF.D(xmm2, xmm2, _v0);
|
||||
xPSHUF.D(xmm3, xmm3, _v0);
|
||||
xPSHUF.D(xmm4, xmm4, _v0);
|
||||
xPSHUF.D(xmm5, xmm5, _v0);
|
||||
}
|
||||
|
||||
// =====================================================================================================
|
||||
// VifUnpackSSE_Base Section
|
||||
// =====================================================================================================
|
||||
VifUnpackSSE_Base::VifUnpackSSE_Base()
|
||||
: dstIndirect(ecx) // parameter 1 of __fastcall
|
||||
, srcIndirect(edx) // parameter 2 of __fastcall
|
||||
, workReg( xmm1 )
|
||||
, destReg( xmm0 )
|
||||
{
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xMovDest() const {
|
||||
if (IsUnmaskedOp()) { xMOVAPS (ptr[dstIndirect], destReg); }
|
||||
else { doMaskWrite(destReg); }
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xShiftR(const xRegisterSSE& regX, int n) const {
|
||||
if (usn) { xPSRL.D(regX, n); }
|
||||
else { xPSRA.D(regX, n); }
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xPMOVXX8(const xRegisterSSE& regX) const {
|
||||
if (usn) xPMOVZX.BD(regX, ptr32[srcIndirect]);
|
||||
else xPMOVSX.BD(regX, ptr32[srcIndirect]);
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xPMOVXX16(const xRegisterSSE& regX) const {
|
||||
if (usn) xPMOVZX.WD(regX, ptr64[srcIndirect]);
|
||||
else xPMOVSX.WD(regX, ptr64[srcIndirect]);
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xUPK_S_32() const {
|
||||
xMOV32 (workReg, ptr32[srcIndirect]);
|
||||
xPSHUF.D (destReg, workReg, _v0);
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xUPK_S_16() const {
|
||||
if (x86caps.hasStreamingSIMD4Extensions) {
|
||||
xPMOVXX16 (workReg);
|
||||
}
|
||||
else {
|
||||
xMOV16 (workReg, ptr32[srcIndirect]);
|
||||
xPUNPCK.LWD(workReg, workReg);
|
||||
xShiftR (workReg, 16);
|
||||
}
|
||||
xPSHUF.D (destReg, workReg, _v0);
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xUPK_S_8() const {
|
||||
if (x86caps.hasStreamingSIMD4Extensions) {
|
||||
xPMOVXX8 (workReg);
|
||||
}
|
||||
else {
|
||||
xMOV8 (workReg, ptr32[srcIndirect]);
|
||||
xPUNPCK.LBW(workReg, workReg);
|
||||
xPUNPCK.LWD(workReg, workReg);
|
||||
xShiftR (workReg, 24);
|
||||
}
|
||||
xPSHUF.D (destReg, workReg, _v0);
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xUPK_V2_32() const {
|
||||
xMOV64 (destReg, ptr32[srcIndirect]);
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xUPK_V2_16() const {
|
||||
if (x86caps.hasStreamingSIMD4Extensions) {
|
||||
xPMOVXX16 (destReg);
|
||||
}
|
||||
else {
|
||||
xMOV32 (destReg, ptr32[srcIndirect]);
|
||||
xPUNPCK.LWD(destReg, destReg);
|
||||
xShiftR (destReg, 16);
|
||||
}
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xUPK_V2_8() const {
|
||||
if (x86caps.hasStreamingSIMD4Extensions) {
|
||||
xPMOVXX8 (destReg);
|
||||
}
|
||||
else {
|
||||
xMOV16 (destReg, ptr32[srcIndirect]);
|
||||
xPUNPCK.LBW(destReg, destReg);
|
||||
xPUNPCK.LWD(destReg, destReg);
|
||||
xShiftR (destReg, 24);
|
||||
}
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xUPK_V3_32() const {
|
||||
xMOV128 (destReg, ptr32[srcIndirect]);
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xUPK_V3_16() const {
|
||||
if (x86caps.hasStreamingSIMD4Extensions) {
|
||||
xPMOVXX16 (destReg);
|
||||
}
|
||||
else {
|
||||
xMOV64 (destReg, ptr32[srcIndirect]);
|
||||
xPUNPCK.LWD(destReg, destReg);
|
||||
xShiftR (destReg, 16);
|
||||
}
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xUPK_V3_8() const {
|
||||
if (x86caps.hasStreamingSIMD4Extensions) {
|
||||
xPMOVXX8 (destReg);
|
||||
}
|
||||
else {
|
||||
xMOV32 (destReg, ptr32[srcIndirect]);
|
||||
xPUNPCK.LBW(destReg, destReg);
|
||||
xPUNPCK.LWD(destReg, destReg);
|
||||
xShiftR (destReg, 24);
|
||||
}
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xUPK_V4_32() const {
|
||||
xMOV128 (destReg, ptr32[srcIndirect]);
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xUPK_V4_16() const {
|
||||
if (x86caps.hasStreamingSIMD4Extensions) {
|
||||
xPMOVXX16 (destReg);
|
||||
}
|
||||
else {
|
||||
xMOV64 (destReg, ptr32[srcIndirect]);
|
||||
xPUNPCK.LWD(destReg, destReg);
|
||||
xShiftR (destReg, 16);
|
||||
}
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xUPK_V4_8() const {
|
||||
if (x86caps.hasStreamingSIMD4Extensions) {
|
||||
xPMOVXX8 (destReg);
|
||||
}
|
||||
else {
|
||||
xMOV32 (destReg, ptr32[srcIndirect]);
|
||||
xPUNPCK.LBW(destReg, destReg);
|
||||
xPUNPCK.LWD(destReg, destReg);
|
||||
xShiftR (destReg, 24);
|
||||
}
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xUPK_V4_5() const {
|
||||
xMOV16 (workReg, ptr32[srcIndirect]);
|
||||
xPSHUF.D (workReg, workReg, _v0);
|
||||
xPSLL.D (workReg, 3); // ABG|R5.000
|
||||
xMOVAPS (destReg, workReg); // x|x|x|R
|
||||
xPSRL.D (workReg, 8); // ABG
|
||||
xPSLL.D (workReg, 3); // AB|G5.000
|
||||
mVUmergeRegs(destReg.Id, workReg.Id, 0x4); // x|x|G|R
|
||||
xPSRL.D (workReg, 8); // AB
|
||||
xPSLL.D (workReg, 3); // A|B5.000
|
||||
mVUmergeRegs(destReg.Id, workReg.Id, 0x2); // x|B|G|R
|
||||
xPSRL.D (workReg, 8); // A
|
||||
xPSLL.D (workReg, 7); // A.0000000
|
||||
mVUmergeRegs(destReg.Id, workReg.Id, 0x1); // A|B|G|R
|
||||
xPSLL.D (destReg, 24); // can optimize to
|
||||
xPSRL.D (destReg, 24); // single AND...
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xUnpack( int upknum ) const
|
||||
{
|
||||
switch( upknum )
|
||||
{
|
||||
case 0: xUPK_S_32(); break;
|
||||
case 1: xUPK_S_16(); break;
|
||||
case 2: xUPK_S_8(); break;
|
||||
|
||||
case 4: xUPK_V2_32(); break;
|
||||
case 5: xUPK_V2_16(); break;
|
||||
case 6: xUPK_V2_8(); break;
|
||||
|
||||
case 8: xUPK_V3_32(); break;
|
||||
case 9: xUPK_V3_16(); break;
|
||||
case 10: xUPK_V3_8(); break;
|
||||
|
||||
case 12: xUPK_V4_32(); break;
|
||||
case 13: xUPK_V4_16(); break;
|
||||
case 14: xUPK_V4_8(); break;
|
||||
case 15: xUPK_V4_5(); break;
|
||||
|
||||
case 3:
|
||||
case 7:
|
||||
case 11:
|
||||
pxFailRel( wxsFormat( L"Vpu/Vif - Invalid Unpack! [%d]", upknum ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// =====================================================================================================
|
||||
// VifUnpackSSE_Simple
|
||||
// =====================================================================================================
|
||||
|
||||
VifUnpackSSE_Simple::VifUnpackSSE_Simple(bool usn_, bool domask_, int curCycle_)
|
||||
{
|
||||
curCycle = curCycle_;
|
||||
usn = usn_;
|
||||
doMask = domask_;
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Simple::doMaskWrite(const xRegisterSSE& regX) const {
|
||||
xMOVAPS(xmm7, ptr[dstIndirect]);
|
||||
int offX = aMin(curCycle, 3);
|
||||
xPAND(regX, ptr32[nVifMask[0][offX]]);
|
||||
xPAND(xmm7, ptr32[nVifMask[1][offX]]);
|
||||
xPOR (regX, ptr32[nVifMask[2][offX]]);
|
||||
xPOR (regX, xmm7);
|
||||
xMOVAPS(ptr[dstIndirect], regX);
|
||||
}
|
||||
|
||||
// ecx = dest, edx = src
|
||||
static void nVifGen(int usn, int mask, int curCycle) {
|
||||
|
||||
int usnpart = usn*2*16;
|
||||
int maskpart = mask*16;
|
||||
|
||||
VifUnpackSSE_Simple vpugen( !!usn, !!mask, curCycle );
|
||||
|
||||
for( int i=0; i<16; ++i )
|
||||
{
|
||||
nVifCall& ucall( nVifUpk[((usnpart+maskpart+i) * 4) + curCycle] );
|
||||
ucall = NULL;
|
||||
if( nVifT[i] == 0 ) continue;
|
||||
|
||||
ucall = (nVifCall)xGetAlignedCallTarget();
|
||||
vpugen.xUnpack(i);
|
||||
vpugen.xMovDest();
|
||||
xRET();
|
||||
|
||||
pxAssert( ((uptr)xGetPtr() - (uptr)nVifUpkExec) < sizeof(nVifUpkExec) );
|
||||
}
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Init()
|
||||
{
|
||||
HostSys::MemProtectStatic(nVifUpkExec, Protect_ReadWrite, false);
|
||||
memset8<0xcc>( nVifUpkExec );
|
||||
|
||||
xSetPtr( nVifUpkExec );
|
||||
|
||||
for (int a = 0; a < 2; a++) {
|
||||
for (int b = 0; b < 2; b++) {
|
||||
for (int c = 0; c < 4; c++) {
|
||||
nVifGen(a, b, c);
|
||||
}}}
|
||||
|
||||
HostSys::MemProtectStatic(nVifUpkExec, Protect_ReadOnly, true);
|
||||
}
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2009 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/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "newVif_UnpackSSE.h"
|
||||
|
||||
#define xMOV8(regX, loc) xMOVSSZX(regX, loc)
|
||||
#define xMOV16(regX, loc) xMOVSSZX(regX, loc)
|
||||
#define xMOV32(regX, loc) xMOVSSZX(regX, loc)
|
||||
#define xMOV64(regX, loc) xMOVUPS(regX, loc)
|
||||
#define xMOV128(regX, loc) xMOVUPS(regX, loc)
|
||||
|
||||
static __pagealigned u8 nVifUpkExec[__pagesize*4];
|
||||
|
||||
// Merges xmm vectors without modifying source reg
|
||||
void mergeVectors(int dest, int src, int temp, int xyzw) {
|
||||
if (x86caps.hasStreamingSIMD4Extensions || (xyzw==15)
|
||||
|| (xyzw==12) || (xyzw==11) || (xyzw==8) || (xyzw==3)) {
|
||||
mVUmergeRegs(dest, src, xyzw);
|
||||
}
|
||||
else {
|
||||
SSE_MOVAPS_XMM_to_XMM(temp, src);
|
||||
mVUmergeRegs(dest, temp, xyzw);
|
||||
}
|
||||
}
|
||||
|
||||
// Loads Row/Col Data from vifRegs instead of g_vifmask
|
||||
// Useful for testing vifReg and g_vifmask inconsistency.
|
||||
void loadRowCol(nVifStruct& v) {
|
||||
xMOVAPS(xmm0, ptr32[&v.vifRegs->r0]);
|
||||
xMOVAPS(xmm1, ptr32[&v.vifRegs->r1]);
|
||||
xMOVAPS(xmm2, ptr32[&v.vifRegs->r2]);
|
||||
xMOVAPS(xmm6, ptr32[&v.vifRegs->r3]);
|
||||
xPSHUF.D(xmm0, xmm0, _v0);
|
||||
xPSHUF.D(xmm1, xmm1, _v0);
|
||||
xPSHUF.D(xmm2, xmm2, _v0);
|
||||
xPSHUF.D(xmm6, xmm6, _v0);
|
||||
mVUmergeRegs(XMM6, XMM0, 8);
|
||||
mVUmergeRegs(XMM6, XMM1, 4);
|
||||
mVUmergeRegs(XMM6, XMM2, 2);
|
||||
xMOVAPS(xmm2, ptr32[&v.vifRegs->c0]);
|
||||
xMOVAPS(xmm3, ptr32[&v.vifRegs->c1]);
|
||||
xMOVAPS(xmm4, ptr32[&v.vifRegs->c2]);
|
||||
xMOVAPS(xmm5, ptr32[&v.vifRegs->c3]);
|
||||
xPSHUF.D(xmm2, xmm2, _v0);
|
||||
xPSHUF.D(xmm3, xmm3, _v0);
|
||||
xPSHUF.D(xmm4, xmm4, _v0);
|
||||
xPSHUF.D(xmm5, xmm5, _v0);
|
||||
}
|
||||
|
||||
// =====================================================================================================
|
||||
// VifUnpackSSE_Base Section
|
||||
// =====================================================================================================
|
||||
VifUnpackSSE_Base::VifUnpackSSE_Base()
|
||||
: dstIndirect(ecx) // parameter 1 of __fastcall
|
||||
, srcIndirect(edx) // parameter 2 of __fastcall
|
||||
, workReg( xmm1 )
|
||||
, destReg( xmm0 )
|
||||
{
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xMovDest() const {
|
||||
if (IsUnmaskedOp()) { xMOVAPS (ptr[dstIndirect], destReg); }
|
||||
else { doMaskWrite(destReg); }
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xShiftR(const xRegisterSSE& regX, int n) const {
|
||||
if (usn) { xPSRL.D(regX, n); }
|
||||
else { xPSRA.D(regX, n); }
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xPMOVXX8(const xRegisterSSE& regX) const {
|
||||
if (usn) xPMOVZX.BD(regX, ptr32[srcIndirect]);
|
||||
else xPMOVSX.BD(regX, ptr32[srcIndirect]);
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xPMOVXX16(const xRegisterSSE& regX) const {
|
||||
if (usn) xPMOVZX.WD(regX, ptr64[srcIndirect]);
|
||||
else xPMOVSX.WD(regX, ptr64[srcIndirect]);
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xUPK_S_32() const {
|
||||
xMOV32 (workReg, ptr32[srcIndirect]);
|
||||
xPSHUF.D (destReg, workReg, _v0);
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xUPK_S_16() const {
|
||||
if (x86caps.hasStreamingSIMD4Extensions) {
|
||||
xPMOVXX16 (workReg);
|
||||
}
|
||||
else {
|
||||
xMOV16 (workReg, ptr32[srcIndirect]);
|
||||
xPUNPCK.LWD(workReg, workReg);
|
||||
xShiftR (workReg, 16);
|
||||
}
|
||||
xPSHUF.D (destReg, workReg, _v0);
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xUPK_S_8() const {
|
||||
if (x86caps.hasStreamingSIMD4Extensions) {
|
||||
xPMOVXX8 (workReg);
|
||||
}
|
||||
else {
|
||||
xMOV8 (workReg, ptr32[srcIndirect]);
|
||||
xPUNPCK.LBW(workReg, workReg);
|
||||
xPUNPCK.LWD(workReg, workReg);
|
||||
xShiftR (workReg, 24);
|
||||
}
|
||||
xPSHUF.D (destReg, workReg, _v0);
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xUPK_V2_32() const {
|
||||
xMOV64 (destReg, ptr32[srcIndirect]);
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xUPK_V2_16() const {
|
||||
if (x86caps.hasStreamingSIMD4Extensions) {
|
||||
xPMOVXX16 (destReg);
|
||||
}
|
||||
else {
|
||||
xMOV32 (destReg, ptr32[srcIndirect]);
|
||||
xPUNPCK.LWD(destReg, destReg);
|
||||
xShiftR (destReg, 16);
|
||||
}
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xUPK_V2_8() const {
|
||||
if (x86caps.hasStreamingSIMD4Extensions) {
|
||||
xPMOVXX8 (destReg);
|
||||
}
|
||||
else {
|
||||
xMOV16 (destReg, ptr32[srcIndirect]);
|
||||
xPUNPCK.LBW(destReg, destReg);
|
||||
xPUNPCK.LWD(destReg, destReg);
|
||||
xShiftR (destReg, 24);
|
||||
}
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xUPK_V3_32() const {
|
||||
xMOV128 (destReg, ptr32[srcIndirect]);
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xUPK_V3_16() const {
|
||||
if (x86caps.hasStreamingSIMD4Extensions) {
|
||||
xPMOVXX16 (destReg);
|
||||
}
|
||||
else {
|
||||
xMOV64 (destReg, ptr32[srcIndirect]);
|
||||
xPUNPCK.LWD(destReg, destReg);
|
||||
xShiftR (destReg, 16);
|
||||
}
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xUPK_V3_8() const {
|
||||
if (x86caps.hasStreamingSIMD4Extensions) {
|
||||
xPMOVXX8 (destReg);
|
||||
}
|
||||
else {
|
||||
xMOV32 (destReg, ptr32[srcIndirect]);
|
||||
xPUNPCK.LBW(destReg, destReg);
|
||||
xPUNPCK.LWD(destReg, destReg);
|
||||
xShiftR (destReg, 24);
|
||||
}
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xUPK_V4_32() const {
|
||||
xMOV128 (destReg, ptr32[srcIndirect]);
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xUPK_V4_16() const {
|
||||
if (x86caps.hasStreamingSIMD4Extensions) {
|
||||
xPMOVXX16 (destReg);
|
||||
}
|
||||
else {
|
||||
xMOV64 (destReg, ptr32[srcIndirect]);
|
||||
xPUNPCK.LWD(destReg, destReg);
|
||||
xShiftR (destReg, 16);
|
||||
}
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xUPK_V4_8() const {
|
||||
if (x86caps.hasStreamingSIMD4Extensions) {
|
||||
xPMOVXX8 (destReg);
|
||||
}
|
||||
else {
|
||||
xMOV32 (destReg, ptr32[srcIndirect]);
|
||||
xPUNPCK.LBW(destReg, destReg);
|
||||
xPUNPCK.LWD(destReg, destReg);
|
||||
xShiftR (destReg, 24);
|
||||
}
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xUPK_V4_5() const {
|
||||
xMOV16 (workReg, ptr32[srcIndirect]);
|
||||
xPSHUF.D (workReg, workReg, _v0);
|
||||
xPSLL.D (workReg, 3); // ABG|R5.000
|
||||
xMOVAPS (destReg, workReg); // x|x|x|R
|
||||
xPSRL.D (workReg, 8); // ABG
|
||||
xPSLL.D (workReg, 3); // AB|G5.000
|
||||
mVUmergeRegs(destReg.Id, workReg.Id, 0x4); // x|x|G|R
|
||||
xPSRL.D (workReg, 8); // AB
|
||||
xPSLL.D (workReg, 3); // A|B5.000
|
||||
mVUmergeRegs(destReg.Id, workReg.Id, 0x2); // x|B|G|R
|
||||
xPSRL.D (workReg, 8); // A
|
||||
xPSLL.D (workReg, 7); // A.0000000
|
||||
mVUmergeRegs(destReg.Id, workReg.Id, 0x1); // A|B|G|R
|
||||
xPSLL.D (destReg, 24); // can optimize to
|
||||
xPSRL.D (destReg, 24); // single AND...
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Base::xUnpack( int upknum ) const
|
||||
{
|
||||
switch( upknum )
|
||||
{
|
||||
case 0: xUPK_S_32(); break;
|
||||
case 1: xUPK_S_16(); break;
|
||||
case 2: xUPK_S_8(); break;
|
||||
|
||||
case 4: xUPK_V2_32(); break;
|
||||
case 5: xUPK_V2_16(); break;
|
||||
case 6: xUPK_V2_8(); break;
|
||||
|
||||
case 8: xUPK_V3_32(); break;
|
||||
case 9: xUPK_V3_16(); break;
|
||||
case 10: xUPK_V3_8(); break;
|
||||
|
||||
case 12: xUPK_V4_32(); break;
|
||||
case 13: xUPK_V4_16(); break;
|
||||
case 14: xUPK_V4_8(); break;
|
||||
case 15: xUPK_V4_5(); break;
|
||||
|
||||
case 3:
|
||||
case 7:
|
||||
case 11:
|
||||
pxFailRel( wxsFormat( L"Vpu/Vif - Invalid Unpack! [%d]", upknum ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// =====================================================================================================
|
||||
// VifUnpackSSE_Simple
|
||||
// =====================================================================================================
|
||||
|
||||
VifUnpackSSE_Simple::VifUnpackSSE_Simple(bool usn_, bool domask_, int curCycle_)
|
||||
{
|
||||
curCycle = curCycle_;
|
||||
usn = usn_;
|
||||
doMask = domask_;
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Simple::doMaskWrite(const xRegisterSSE& regX) const {
|
||||
xMOVAPS(xmm7, ptr[dstIndirect]);
|
||||
int offX = aMin(curCycle, 3);
|
||||
xPAND(regX, ptr32[nVifMask[0][offX]]);
|
||||
xPAND(xmm7, ptr32[nVifMask[1][offX]]);
|
||||
xPOR (regX, ptr32[nVifMask[2][offX]]);
|
||||
xPOR (regX, xmm7);
|
||||
xMOVAPS(ptr[dstIndirect], regX);
|
||||
}
|
||||
|
||||
// ecx = dest, edx = src
|
||||
static void nVifGen(int usn, int mask, int curCycle) {
|
||||
|
||||
int usnpart = usn*2*16;
|
||||
int maskpart = mask*16;
|
||||
|
||||
VifUnpackSSE_Simple vpugen( !!usn, !!mask, curCycle );
|
||||
|
||||
for( int i=0; i<16; ++i )
|
||||
{
|
||||
nVifCall& ucall( nVifUpk[((usnpart+maskpart+i) * 4) + curCycle] );
|
||||
ucall = NULL;
|
||||
if( nVifT[i] == 0 ) continue;
|
||||
|
||||
ucall = (nVifCall)xGetAlignedCallTarget();
|
||||
vpugen.xUnpack(i);
|
||||
vpugen.xMovDest();
|
||||
xRET();
|
||||
|
||||
pxAssert( ((uptr)xGetPtr() - (uptr)nVifUpkExec) < sizeof(nVifUpkExec) );
|
||||
}
|
||||
}
|
||||
|
||||
void VifUnpackSSE_Init()
|
||||
{
|
||||
HostSys::MemProtectStatic(nVifUpkExec, Protect_ReadWrite, false);
|
||||
memset8<0xcc>( nVifUpkExec );
|
||||
|
||||
xSetPtr( nVifUpkExec );
|
||||
|
||||
for (int a = 0; a < 2; a++) {
|
||||
for (int b = 0; b < 2; b++) {
|
||||
for (int c = 0; c < 4; c++) {
|
||||
nVifGen(a, b, c);
|
||||
}}}
|
||||
|
||||
HostSys::MemProtectStatic(nVifUpkExec, Protect_ReadOnly, true);
|
||||
}
|
||||
|
|
|
@ -1,145 +1,145 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2009 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
|
||||
|
||||
#include "Common.h"
|
||||
#include "Vif_Dma.h"
|
||||
#include "newVif.h"
|
||||
|
||||
#include <xmmintrin.h>
|
||||
#include <emmintrin.h>
|
||||
|
||||
using namespace x86Emitter;
|
||||
|
||||
extern void mergeVectors(int dest, int src, int temp, int xyzw);
|
||||
extern void loadRowCol(nVifStruct& v);
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// VifUnpackSSE_Base
|
||||
// --------------------------------------------------------------------------------------
|
||||
class VifUnpackSSE_Base
|
||||
{
|
||||
public:
|
||||
bool usn; // unsigned flag
|
||||
bool doMask; // masking write enable flag
|
||||
|
||||
protected:
|
||||
xAddressInfo dstIndirect;
|
||||
xAddressInfo srcIndirect;
|
||||
xRegisterSSE workReg;
|
||||
xRegisterSSE destReg;
|
||||
|
||||
public:
|
||||
VifUnpackSSE_Base();
|
||||
virtual ~VifUnpackSSE_Base() throw() {}
|
||||
|
||||
virtual void xUnpack( int upktype ) const;
|
||||
virtual bool IsUnmaskedOp() const=0;
|
||||
virtual void xMovDest() const;
|
||||
|
||||
protected:
|
||||
virtual void doMaskWrite(const xRegisterSSE& regX ) const=0;
|
||||
|
||||
virtual void xShiftR(const xRegisterSSE& regX, int n) const;
|
||||
virtual void xPMOVXX8(const xRegisterSSE& regX) const;
|
||||
virtual void xPMOVXX16(const xRegisterSSE& regX) const;
|
||||
|
||||
virtual void xUPK_S_32() const;
|
||||
virtual void xUPK_S_16() const;
|
||||
virtual void xUPK_S_8() const;
|
||||
|
||||
virtual void xUPK_V2_32() const;
|
||||
virtual void xUPK_V2_16() const;
|
||||
virtual void xUPK_V2_8() const;
|
||||
|
||||
virtual void xUPK_V3_32() const;
|
||||
virtual void xUPK_V3_16() const;
|
||||
virtual void xUPK_V3_8() const;
|
||||
|
||||
virtual void xUPK_V4_32() const;
|
||||
virtual void xUPK_V4_16() const;
|
||||
virtual void xUPK_V4_8() const;
|
||||
virtual void xUPK_V4_5() const;
|
||||
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// VifUnpackSSE_Simple
|
||||
// --------------------------------------------------------------------------------------
|
||||
class VifUnpackSSE_Simple : public VifUnpackSSE_Base
|
||||
{
|
||||
typedef VifUnpackSSE_Base _parent;
|
||||
|
||||
public:
|
||||
int curCycle;
|
||||
|
||||
public:
|
||||
VifUnpackSSE_Simple(bool usn_, bool domask_, int curCycle_);
|
||||
virtual ~VifUnpackSSE_Simple() throw() {}
|
||||
|
||||
virtual bool IsUnmaskedOp() const{ return !doMask; }
|
||||
|
||||
protected:
|
||||
virtual void doMaskWrite(const xRegisterSSE& regX ) const;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// VifUnpackSSE_Dynarec
|
||||
// --------------------------------------------------------------------------------------
|
||||
class VifUnpackSSE_Dynarec : public VifUnpackSSE_Base
|
||||
{
|
||||
typedef VifUnpackSSE_Base _parent;
|
||||
|
||||
public:
|
||||
bool isFill;
|
||||
int doMode; // two bit value representing... something!
|
||||
|
||||
protected:
|
||||
const nVifStruct& v; // vif0 or vif1
|
||||
const nVifBlock& vB; // some pre-collected data from VifStruct
|
||||
int vCL; // internal copy of vif->cl
|
||||
|
||||
public:
|
||||
VifUnpackSSE_Dynarec(const nVifStruct& vif_, const nVifBlock& vifBlock_);
|
||||
VifUnpackSSE_Dynarec(const VifUnpackSSE_Dynarec& src) // copy constructor
|
||||
: _parent(src)
|
||||
, v(src.v)
|
||||
, vB(src.vB)
|
||||
{
|
||||
isFill = src.isFill;
|
||||
vCL = src.vCL;
|
||||
}
|
||||
|
||||
virtual ~VifUnpackSSE_Dynarec() throw() {}
|
||||
|
||||
virtual bool IsUnmaskedOp() const{ return !doMode && !doMask; }
|
||||
|
||||
void CompileRoutine();
|
||||
|
||||
protected:
|
||||
virtual void doMaskWrite(const xRegisterSSE& regX) const;
|
||||
void SetMasks(int cS) const;
|
||||
void writeBackRow() const;
|
||||
|
||||
static VifUnpackSSE_Dynarec FillingWrite( const VifUnpackSSE_Dynarec& src )
|
||||
{
|
||||
VifUnpackSSE_Dynarec fillingWrite( src );
|
||||
fillingWrite.doMask = true;
|
||||
fillingWrite.doMode = 0;
|
||||
return fillingWrite;
|
||||
}
|
||||
};
|
||||
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2009 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
|
||||
|
||||
#include "Common.h"
|
||||
#include "Vif_Dma.h"
|
||||
#include "newVif.h"
|
||||
|
||||
#include <xmmintrin.h>
|
||||
#include <emmintrin.h>
|
||||
|
||||
using namespace x86Emitter;
|
||||
|
||||
extern void mergeVectors(int dest, int src, int temp, int xyzw);
|
||||
extern void loadRowCol(nVifStruct& v);
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// VifUnpackSSE_Base
|
||||
// --------------------------------------------------------------------------------------
|
||||
class VifUnpackSSE_Base
|
||||
{
|
||||
public:
|
||||
bool usn; // unsigned flag
|
||||
bool doMask; // masking write enable flag
|
||||
|
||||
protected:
|
||||
xAddressInfo dstIndirect;
|
||||
xAddressInfo srcIndirect;
|
||||
xRegisterSSE workReg;
|
||||
xRegisterSSE destReg;
|
||||
|
||||
public:
|
||||
VifUnpackSSE_Base();
|
||||
virtual ~VifUnpackSSE_Base() throw() {}
|
||||
|
||||
virtual void xUnpack( int upktype ) const;
|
||||
virtual bool IsUnmaskedOp() const=0;
|
||||
virtual void xMovDest() const;
|
||||
|
||||
protected:
|
||||
virtual void doMaskWrite(const xRegisterSSE& regX ) const=0;
|
||||
|
||||
virtual void xShiftR(const xRegisterSSE& regX, int n) const;
|
||||
virtual void xPMOVXX8(const xRegisterSSE& regX) const;
|
||||
virtual void xPMOVXX16(const xRegisterSSE& regX) const;
|
||||
|
||||
virtual void xUPK_S_32() const;
|
||||
virtual void xUPK_S_16() const;
|
||||
virtual void xUPK_S_8() const;
|
||||
|
||||
virtual void xUPK_V2_32() const;
|
||||
virtual void xUPK_V2_16() const;
|
||||
virtual void xUPK_V2_8() const;
|
||||
|
||||
virtual void xUPK_V3_32() const;
|
||||
virtual void xUPK_V3_16() const;
|
||||
virtual void xUPK_V3_8() const;
|
||||
|
||||
virtual void xUPK_V4_32() const;
|
||||
virtual void xUPK_V4_16() const;
|
||||
virtual void xUPK_V4_8() const;
|
||||
virtual void xUPK_V4_5() const;
|
||||
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// VifUnpackSSE_Simple
|
||||
// --------------------------------------------------------------------------------------
|
||||
class VifUnpackSSE_Simple : public VifUnpackSSE_Base
|
||||
{
|
||||
typedef VifUnpackSSE_Base _parent;
|
||||
|
||||
public:
|
||||
int curCycle;
|
||||
|
||||
public:
|
||||
VifUnpackSSE_Simple(bool usn_, bool domask_, int curCycle_);
|
||||
virtual ~VifUnpackSSE_Simple() throw() {}
|
||||
|
||||
virtual bool IsUnmaskedOp() const{ return !doMask; }
|
||||
|
||||
protected:
|
||||
virtual void doMaskWrite(const xRegisterSSE& regX ) const;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// VifUnpackSSE_Dynarec
|
||||
// --------------------------------------------------------------------------------------
|
||||
class VifUnpackSSE_Dynarec : public VifUnpackSSE_Base
|
||||
{
|
||||
typedef VifUnpackSSE_Base _parent;
|
||||
|
||||
public:
|
||||
bool isFill;
|
||||
int doMode; // two bit value representing... something!
|
||||
|
||||
protected:
|
||||
const nVifStruct& v; // vif0 or vif1
|
||||
const nVifBlock& vB; // some pre-collected data from VifStruct
|
||||
int vCL; // internal copy of vif->cl
|
||||
|
||||
public:
|
||||
VifUnpackSSE_Dynarec(const nVifStruct& vif_, const nVifBlock& vifBlock_);
|
||||
VifUnpackSSE_Dynarec(const VifUnpackSSE_Dynarec& src) // copy constructor
|
||||
: _parent(src)
|
||||
, v(src.v)
|
||||
, vB(src.vB)
|
||||
{
|
||||
isFill = src.isFill;
|
||||
vCL = src.vCL;
|
||||
}
|
||||
|
||||
virtual ~VifUnpackSSE_Dynarec() throw() {}
|
||||
|
||||
virtual bool IsUnmaskedOp() const{ return !doMode && !doMask; }
|
||||
|
||||
void CompileRoutine();
|
||||
|
||||
protected:
|
||||
virtual void doMaskWrite(const xRegisterSSE& regX) const;
|
||||
void SetMasks(int cS) const;
|
||||
void writeBackRow() const;
|
||||
|
||||
static VifUnpackSSE_Dynarec FillingWrite( const VifUnpackSSE_Dynarec& src )
|
||||
{
|
||||
VifUnpackSSE_Dynarec fillingWrite( src );
|
||||
fillingWrite.doMask = true;
|
||||
fillingWrite.doMode = 0;
|
||||
return fillingWrite;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue