diff --git a/pcsx2/Dmac.h b/pcsx2/Dmac.h index 93047d4a40..1b5c7689f7 100644 --- a/pcsx2/Dmac.h +++ b/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 - diff --git a/pcsx2/Hw.h b/pcsx2/Hw.h index d676b2d148..228def8a76 100644 --- a/pcsx2/Hw.h +++ b/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 diff --git a/pcsx2/IPU/IPU.h b/pcsx2/IPU/IPU.h index f3036edd04..37570934b6 100644 --- a/pcsx2/IPU/IPU.h +++ b/pcsx2/IPU/IPU.h @@ -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 diff --git a/pcsx2/Vif.h b/pcsx2/Vif.h index ddcb2defa5..2fe1255a70 100644 --- a/pcsx2/Vif.h +++ b/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 diff --git a/pcsx2/gui/FrameForGS.cpp b/pcsx2/gui/FrameForGS.cpp index ac6662c422..6ad7948acd 100644 --- a/pcsx2/gui/FrameForGS.cpp +++ b/pcsx2/gui/FrameForGS.cpp @@ -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() diff --git a/pcsx2/x86/newVif_Dynarec.cpp b/pcsx2/x86/newVif_Dynarec.cpp index e5d7d7dad2..3a5f81742e 100644 --- a/pcsx2/x86/newVif_Dynarec.cpp +++ b/pcsx2/x86/newVif_Dynarec.cpp @@ -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 . - */ - -// 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 . + */ + +// 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); +} diff --git a/pcsx2/x86/newVif_UnpackSSE.cpp b/pcsx2/x86/newVif_UnpackSSE.cpp index 9ddd912e37..ea479efdd2 100644 --- a/pcsx2/x86/newVif_UnpackSSE.cpp +++ b/pcsx2/x86/newVif_UnpackSSE.cpp @@ -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 . - */ - -#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 . + */ + +#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); +} diff --git a/pcsx2/x86/newVif_UnpackSSE.h b/pcsx2/x86/newVif_UnpackSSE.h index 01629630c4..c384c05eeb 100644 --- a/pcsx2/x86/newVif_UnpackSSE.h +++ b/pcsx2/x86/newVif_UnpackSSE.h @@ -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 . - */ - -#pragma once - -#include "Common.h" -#include "Vif_Dma.h" -#include "newVif.h" - -#include -#include - -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 . + */ + +#pragma once + +#include "Common.h" +#include "Vif_Dma.h" +#include "newVif.h" + +#include +#include + +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; + } +}; +