/* Pcsx2 - Pc Ps2 Emulator * Copyright (C) 2002-2005 Pcsx2 Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include "Common.h" #include "Vif.h" #include "VUmicro.h" #include "GS.h" #include "VifDma.h" #include #define gif ((DMACh*)&PS2MEM_HW[0xA000]) // Extern variables extern VIFregisters *_vifRegs; extern vifStruct *_vif; extern u32* _vifMaskRegs; extern u32 g_vifRow0[4], g_vifCol0[4], g_vifRow1[4], g_vifCol1[4]; extern u32* _vifRow; vifStruct vif0, vif1; PCSX2_ALIGNED16(u32 g_vif1Masks[64]); PCSX2_ALIGNED16(u32 g_vif0Masks[64]); u32 g_vif1HasMask3[4] = {0}, g_vif0HasMask3[4] = {0}; // Generic constants static const unsigned int VIF0intc = 4; static const unsigned int VIF1intc = 5; static const unsigned int VIF0dmanum = 0; static const unsigned int VIF1dmanum = 1; #ifdef _WIN32 extern HANDLE g_hGsEvent; #else extern pthread_cond_t g_condGsEvent; #endif int g_vifCycles = 0; extern void * memcpy_amd(void *dest, const void *src, size_t n); typedef void (*UNPACKFUNCTYPE)( u32 *dest, u32 *data ); typedef int (*UNPACKPARTFUNCTYPE)( u32 *dest, u32 *data, int size ); void (*Vif1CMDTLB[82])(); void (*Vif0CMDTLB[75])(); int (*Vif1TransTLB[128])(u32 *data, int size); int (*Vif0TransTLB[128])(u32 *data, int size); typedef struct { UNPACKFUNCTYPE funcU; UNPACKFUNCTYPE funcS; UNPACKPARTFUNCTYPE funcUpart; UNPACKPARTFUNCTYPE funcSpart; int bsize; // currently unused int dsize; // byte size of one channel int gsize; // size of data in bytes used for each write cycle int qsize; // used for unpack parts, num of vectors that // will be decompressed from data for 1 cycle } VIFUnpackFuncTable; /* block size; data size; group size; qword size; */ #define _UNPACK_TABLE32(name, bsize, dsize, gsize, qsize) \ { UNPACK_##name, UNPACK_##name, \ UNPACK_##name##part, UNPACK_##name##part, \ bsize, dsize, gsize, qsize }, #define _UNPACK_TABLE(name, bsize, dsize, gsize, qsize) \ { UNPACK_##name##u, UNPACK_##name##s, \ UNPACK_##name##upart, UNPACK_##name##spart, \ bsize, dsize, gsize, qsize }, // Main table for function unpacking static const VIFUnpackFuncTable VIFfuncTable[16] = { _UNPACK_TABLE32(S_32, 1, 4, 4, 4) // 0x0 - S-32 _UNPACK_TABLE(S_16, 2, 2, 2, 4) // 0x1 - S-16 _UNPACK_TABLE(S_8, 4, 1, 1, 4) // 0x2 - S-8 { NULL, NULL, NULL, NULL, 0, 0, 0, 0 }, // 0x3 _UNPACK_TABLE32(V2_32, 24, 4, 8, 2) // 0x4 - V2-32 _UNPACK_TABLE(V2_16, 12, 2, 4, 2) // 0x5 - V2-16 _UNPACK_TABLE(V2_8, 6, 1, 2, 2) // 0x6 - V2-8 { NULL, NULL, NULL, NULL, 0, 0, 0, 0 }, // 0x7 _UNPACK_TABLE32(V3_32, 36, 4, 12, 3) // 0x8 - V3-32 _UNPACK_TABLE(V3_16, 18, 2, 6, 3) // 0x9 - V3-16 _UNPACK_TABLE(V3_8, 9, 1, 3, 3) // 0xA - V3-8 { NULL, NULL, NULL, NULL, 0, 0, 0, 0 }, // 0xB _UNPACK_TABLE32(V4_32, 48, 4, 16, 4) // 0xC - V4-32 _UNPACK_TABLE(V4_16, 24, 2, 8, 4) // 0xD - V4-16 _UNPACK_TABLE(V4_8, 12, 1, 4, 4) // 0xE - V4-8 _UNPACK_TABLE32(V4_5, 6, 2, 2, 4) // 0xF - V4-5 }; #if (defined(__i386__) || defined(__x86_64__)) typedef struct { // regular 0, 1, 2; mask 0, 1, 2 UNPACKPARTFUNCTYPE funcU[9], funcS[9]; } VIFSSEUnpackTable; #define DECL_UNPACK_TABLE_SSE(name, sign) \ extern int UNPACK_SkippingWrite_##name##_##sign##_Regular_0(u32* dest, u32* data, int dmasize); \ extern int UNPACK_SkippingWrite_##name##_##sign##_Regular_1(u32* dest, u32* data, int dmasize); \ extern int UNPACK_SkippingWrite_##name##_##sign##_Regular_2(u32* dest, u32* data, int dmasize); \ extern int UNPACK_SkippingWrite_##name##_##sign##_Mask_0(u32* dest, u32* data, int dmasize); \ extern int UNPACK_SkippingWrite_##name##_##sign##_Mask_1(u32* dest, u32* data, int dmasize); \ extern int UNPACK_SkippingWrite_##name##_##sign##_Mask_2(u32* dest, u32* data, int dmasize); \ extern int UNPACK_SkippingWrite_##name##_##sign##_WriteMask_0(u32* dest, u32* data, int dmasize); \ extern int UNPACK_SkippingWrite_##name##_##sign##_WriteMask_1(u32* dest, u32* data, int dmasize); \ extern int UNPACK_SkippingWrite_##name##_##sign##_WriteMask_2(u32* dest, u32* data, int dmasize); \ #define _UNPACK_TABLE_SSE(name, sign) \ UNPACK_SkippingWrite_##name##_##sign##_Regular_0, \ UNPACK_SkippingWrite_##name##_##sign##_Regular_1, \ UNPACK_SkippingWrite_##name##_##sign##_Regular_2, \ UNPACK_SkippingWrite_##name##_##sign##_Mask_0, \ UNPACK_SkippingWrite_##name##_##sign##_Mask_1, \ UNPACK_SkippingWrite_##name##_##sign##_Mask_2, \ UNPACK_SkippingWrite_##name##_##sign##_WriteMask_0, \ UNPACK_SkippingWrite_##name##_##sign##_WriteMask_1, \ UNPACK_SkippingWrite_##name##_##sign##_WriteMask_2 \ #define _UNPACK_TABLE_SSE_NULL \ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL // Main table for function unpacking DECL_UNPACK_TABLE_SSE(S_32, u); DECL_UNPACK_TABLE_SSE(S_16, u); DECL_UNPACK_TABLE_SSE(S_8, u); DECL_UNPACK_TABLE_SSE(S_16, s); DECL_UNPACK_TABLE_SSE(S_8, s); DECL_UNPACK_TABLE_SSE(V2_32, u); DECL_UNPACK_TABLE_SSE(V2_16, u); DECL_UNPACK_TABLE_SSE(V2_8, u); DECL_UNPACK_TABLE_SSE(V2_16, s); DECL_UNPACK_TABLE_SSE(V2_8, s); DECL_UNPACK_TABLE_SSE(V3_32, u); DECL_UNPACK_TABLE_SSE(V3_16, u); DECL_UNPACK_TABLE_SSE(V3_8, u); DECL_UNPACK_TABLE_SSE(V3_16, s); DECL_UNPACK_TABLE_SSE(V3_8, s); DECL_UNPACK_TABLE_SSE(V4_32, u); DECL_UNPACK_TABLE_SSE(V4_16, u); DECL_UNPACK_TABLE_SSE(V4_8, u); DECL_UNPACK_TABLE_SSE(V4_16, s); DECL_UNPACK_TABLE_SSE(V4_8, s); DECL_UNPACK_TABLE_SSE(V4_5, u); static const VIFSSEUnpackTable VIFfuncTableSSE[16] = { { _UNPACK_TABLE_SSE(S_32, u), _UNPACK_TABLE_SSE(S_32, u) }, { _UNPACK_TABLE_SSE(S_16, u), _UNPACK_TABLE_SSE(S_16, s) }, { _UNPACK_TABLE_SSE(S_8, u), _UNPACK_TABLE_SSE(S_8, s) }, { _UNPACK_TABLE_SSE_NULL, _UNPACK_TABLE_SSE_NULL }, { _UNPACK_TABLE_SSE(V2_32, u), _UNPACK_TABLE_SSE(V2_32, u) }, { _UNPACK_TABLE_SSE(V2_16, u), _UNPACK_TABLE_SSE(V2_16, s) }, { _UNPACK_TABLE_SSE(V2_8, u), _UNPACK_TABLE_SSE(V2_8, s) }, { _UNPACK_TABLE_SSE_NULL, _UNPACK_TABLE_SSE_NULL }, { _UNPACK_TABLE_SSE(V3_32, u), _UNPACK_TABLE_SSE(V3_32, u) }, { _UNPACK_TABLE_SSE(V3_16, u), _UNPACK_TABLE_SSE(V3_16, s) }, { _UNPACK_TABLE_SSE(V3_8, u), _UNPACK_TABLE_SSE(V3_8, s) }, { _UNPACK_TABLE_SSE_NULL, _UNPACK_TABLE_SSE_NULL }, { _UNPACK_TABLE_SSE(V4_32, u), _UNPACK_TABLE_SSE(V4_32, u) }, { _UNPACK_TABLE_SSE(V4_16, u), _UNPACK_TABLE_SSE(V4_16, s) }, { _UNPACK_TABLE_SSE(V4_8, u), _UNPACK_TABLE_SSE(V4_8, s) }, { _UNPACK_TABLE_SSE(V4_5, u), _UNPACK_TABLE_SSE(V4_5, u) }, }; #endif void vif0FLUSH(); void vif1FLUSH(); void vifDmaInit() { } __inline static int _limit( int a, int max ) { return ( a > max ? max : a ); } extern void DummyExecuteVU1Block(void); //#define VIFUNPACKDEBUG //enable unpack debugging output static void ProcessMemSkip(int size, unsigned int unpackType, const unsigned int VIFdmanum){ const VIFUnpackFuncTable *unpack; vifStruct *vif; unpack = &VIFfuncTable[ unpackType ]; // varLog |= 0x00000400; if (VIFdmanum == 0) vif = &vif0; else vif = &vif1; switch(unpackType){ case 0x0: vif->tag.addr += size*4; #ifdef VIFUNPACKDEBUG SysPrintf("Processing S-32 skip, size = %d\n", size); #endif break; case 0x1: vif->tag.addr += size*8; #ifdef VIFUNPACKDEBUG SysPrintf("Processing S-16 skip, size = %d\n", size); #endif break; case 0x2: vif->tag.addr += size*16; #ifdef VIFUNPACKDEBUG SysPrintf("Processing S-8 skip, size = %d\n", size); #endif break; case 0x4: vif->tag.addr += size + ((size / unpack->gsize) * 4); #ifdef VIFUNPACKDEBUG SysPrintf("Processing V2-32 skip, size = %d\n", size); #endif break; case 0x5: vif->tag.addr += (size * 2) + ((size / unpack->gsize) * 4); #ifdef VIFUNPACKDEBUG SysPrintf("Processing V2-16 skip, size = %d\n", size); #endif break; case 0x6: vif->tag.addr += (size * 4) + ((size / unpack->gsize) * 4); #ifdef VIFUNPACKDEBUG SysPrintf("Processing V2-8 skip, size = %d\n", size); #endif break; case 0x8: vif->tag.addr += size + ((size / unpack->gsize) * 4); #ifdef VIFUNPACKDEBUG SysPrintf("Processing V3-32 skip, size = %d\n", size); #endif break; case 0x9: vif->tag.addr += (size * 2) + ((size / unpack->gsize) * 4); #ifdef VIFUNPACKDEBUG SysPrintf("Processing V3-16 skip, size = %d\n", size); #endif break; case 0xA: vif->tag.addr += (size * 4) + ((size / unpack->gsize) * 4); #ifdef VIFUNPACKDEBUG SysPrintf("Processing V3-8 skip, size = %d\n", size); #endif break; case 0xC: vif->tag.addr += size; #ifdef VIFUNPACKDEBUG SysPrintf("Processing V4-32 skip, size = %d, CL = %d, WL = %d\n", size, vif1Regs->cycle.cl, vif1Regs->cycle.wl); #endif break; case 0xD: vif->tag.addr += size * 2; #ifdef VIFUNPACKDEBUG SysPrintf("Processing V4-16 skip, size = %d\n", size); #endif break; case 0xE: vif->tag.addr += size * 4; #ifdef VIFUNPACKDEBUG SysPrintf("Processing V4-8 skip, size = %d\n", size); #endif break; case 0xF: vif->tag.addr += size * 8; #ifdef VIFUNPACKDEBUG SysPrintf("Processing V4-5 skip, size = %d\n", size); #endif break; default: SysPrintf("Invalid unpack type %x\n", unpackType); break; } } #ifdef _MSC_VER //#define __MMX__ //#define __SSE__ #include #include #endif static void VIFunpack(u32 *data, vifCode *v, int size, const unsigned int VIFdmanum) { u32 *dest; unsigned int unpackType; UNPACKFUNCTYPE func; UNPACKPARTFUNCTYPE funcP; const VIFUnpackFuncTable *ft; vifStruct *vif; VIFregisters *vifRegs; VURegs * VU; u8 *cdata = (u8*)data; int memsize; #ifdef _MSC_VER _mm_prefetch((char*)data, _MM_HINT_NTA); #endif if (VIFdmanum == 0) { VU = &VU0; vif = &vif0; vifRegs = vif0Regs; memsize = 0x1000; assert( v->addr < 0x1000 ); v->addr &= 0xfff; } else { VU = &VU1; vif = &vif1; vifRegs = vif1Regs; memsize = 0x4000; assert( v->addr < 0x4000 ); v->addr &= 0x3fff; if( Cpu->ExecuteVU1Block == DummyExecuteVU1Block ) { // don't process since the frame is dummy vif->tag.addr += (size / (VIFfuncTable[ vif->cmd & 0xf ].gsize* vifRegs->cycle.wl)) * ((vifRegs->cycle.cl - vifRegs->cycle.wl)*16); return; } } dest = (u32*)(VU->Mem + v->addr); #ifdef VIF_LOG VIF_LOG("VIF%d UNPACK: Mode=%x, v->size=%d, size=%d, v->addr=%x\n", VIFdmanum, v->cmd & 0xf, v->size, size, v->addr ); #endif /* if (vifRegs->cycle.cl > vifRegs->cycle.wl) { SysPrintf( "VIF%d UNPACK: Mode=%x, v->size=%d, size=%d, v->addr=%x\n", VIFdmanum, v->cmd & 0xf, v->size, size, v->addr ); }*/ #ifdef _DEBUG if (v->size != size) { #ifdef VIF_LOG VIF_LOG("*PCSX2*: warning v->size != size\n"); #endif } if ((v->addr+size*4) > memsize) { SysPrintf("*PCSX2*: fixme unpack overflow\n"); SysPrintf( "VIF%d UNPACK: Mode=%x, v->size=%d, size=%d, v->addr=%x\n", VIFdmanum, v->cmd & 0xf, v->size, size, v->addr ); } #endif // The unpack type unpackType = v->cmd & 0xf; /*if (v->size != size) { SysPrintf("*PCSX2*: v->size = %d, size = %d mode = %x\n", v->size, size, unpackType); }*/ #ifdef VIFUNPACKDEBUG if (size == 0) { SysPrintf("*PCSX2*: Unpack %x with size 0!! v->size = %d cl = %d, wl = %d, mode %d mask %x\n", v->cmd, v->size, vifRegs->cycle.cl, vifRegs->cycle.wl, vifRegs->mode, vifRegs->mask); //return; } #endif if(unpackType == 0xC && vifRegs->cycle.cl == vifRegs->cycle.wl) { // v4-32 if(vifRegs->mode == 0 && !(vifRegs->code & 0x10000000)){ if (v->size != size)ProcessMemSkip(size << 2, unpackType, VIFdmanum); memcpy_amd((u8*)dest, cdata, size << 2); size = 0; return; } } #ifdef _MSC_VER _mm_prefetch((char*)data+128, _MM_HINT_NTA); #endif _vifRegs = (VIFregisters*)vifRegs; _vifMaskRegs = VIFdmanum ? g_vif1Masks : g_vif0Masks; _vif = vif; _vifRow = VIFdmanum ? g_vifRow1 : g_vifRow0; // Unpacking //vif->wl = 0; vif->cl = 0; if (v->size != size)ProcessMemSkip(size<<2, unpackType, VIFdmanum); size<<= 2; #ifdef _DEBUG memsize = size; #endif if( _vifRegs->offset > 0) { int destinc, unpacksize; #ifdef VIFUNPACKDEBUG SysPrintf("aligning packet size = %d offset %d\n", size, vifRegs->offset); #endif // SSE doesn't handle such small data ft = &VIFfuncTable[ unpackType ]; func = vif->usn ? ft->funcU : ft->funcS; funcP = vif->usn ? ft->funcUpart : ft->funcSpart; if(vifRegs->offset < (u32)ft->qsize){ unpacksize = (ft->qsize - vifRegs->offset); } else { unpacksize = 0; SysPrintf("Unpack align offset = 0\n"); } destinc = 4 - vifRegs->offset; funcP(dest, (u32*)cdata, unpacksize); size -= unpacksize*ft->dsize; cdata += unpacksize*ft->dsize; vifRegs->num--; ++vif->cl; if (vif->cl == vifRegs->cycle.wl) { if(vifRegs->cycle.cl != vifRegs->cycle.wl){ dest += ((vifRegs->cycle.cl - vifRegs->cycle.wl)<<2) + destinc; vif->tag.addr += ((vifRegs->cycle.cl - vifRegs->cycle.wl)*16); } else { dest += destinc; } vif->cl = 0; } else { dest += destinc; } #ifdef VIFUNPACKDEBUG SysPrintf("aligning packet done size = %d offset %d\n", size, vifRegs->offset); #endif //} //skipmeminc += (((vifRegs->cycle.cl - vifRegs->cycle.wl)<<2)*4) * skipped; } if (vifRegs->cycle.cl >= vifRegs->cycle.wl && size > 0 && vifRegs->num > 0) { // skipping write #ifdef _DEBUG static s_count=0; #endif u32* olddest = dest; ft = &VIFfuncTable[ unpackType ]; if( !(v->addr&0xf) && cpucaps.hasStreamingSIMD2Extensions ) { const UNPACKPARTFUNCTYPE* pfn; int writemask; //static LARGE_INTEGER lbase, lfinal; //QueryPerformanceCounter(&lbase); u32 oldcycle = -1; FreezeXMMRegs(1); // u16 tempdata[4] = { 0x8000, 0x7fff, 0x1010, 0xd0d0 }; // vifRegs->cycle.cl = 4; // vifRegs->cycle.wl = 1; // SetNewMask(g_vif1Masks, g_vif1HasMask3, 0x3f, ~0x3f); // memset(dest, 0xcd, 64*4); // VIFfuncTableSSE[1].funcS[6](dest, (u32*)tempdata, 8); #ifdef _MSC_VER if( VIFdmanum ) { __asm movaps XMM_ROW, qword ptr [g_vifRow1] __asm movaps XMM_COL, qword ptr [g_vifCol1] } else { __asm movaps XMM_ROW, qword ptr [g_vifRow0] __asm movaps XMM_COL, qword ptr [g_vifCol0] } #else if( VIFdmanum ) { __asm__(".intel_syntax\n" "movaps %%xmm6, qword ptr [%0]\n" "movaps %%xmm7, qword ptr [%1]\n" ".att_syntax\n" : :"i"(g_vifRow1), "i"(g_vifCol1) ); } else { __asm__(".intel_syntax\n" "movaps %%xmm6, qword ptr [%0]\n" "movaps %%xmm7, qword ptr [%1]\n" ".att_syntax\n" : : "i"(g_vifRow0), "i"(g_vifCol0) ); } #endif if( vifRegs->cycle.cl == 0 || vifRegs->cycle.wl == 0 || (vifRegs->cycle.cl == vifRegs->cycle.wl && !(vifRegs->code&0x10000000)) ) { oldcycle = *(u32*)&vifRegs->cycle; vifRegs->cycle.cl = vifRegs->cycle.wl = 1; } size = min(size, (int)vifRegs->num*ft->gsize); pfn = vif->usn ? VIFfuncTableSSE[unpackType].funcU: VIFfuncTableSSE[unpackType].funcS; writemask = VIFdmanum ? g_vif1HasMask3[min(vifRegs->cycle.wl,3)] : g_vif0HasMask3[min(vifRegs->cycle.wl,3)]; writemask = pfn[(((vifRegs->code & 0x10000000)>>28)<mode](dest, (u32*)cdata, size); if( oldcycle != -1 ) *(u32*)&vifRegs->cycle = oldcycle; // if size is left over, update the src,dst pointers if( writemask > 0 ) { int left; left = (size-writemask)/ft->gsize; cdata += size-writemask; dest = (u32*)((u8*)dest + ((left/vifRegs->cycle.wl)*vifRegs->cycle.cl + left%vifRegs->cycle.wl)*16); vifRegs->num -= left; } else vifRegs->num -= size/ft->gsize; vif->tag.addr += (size / (ft->gsize* vifRegs->cycle.wl)) * ((vifRegs->cycle.cl - vifRegs->cycle.wl)*16); size = writemask; _vifRegs->r0 = _vifRow[0]; _vifRegs->r1 = _vifRow[1]; _vifRegs->r2 = _vifRow[2]; _vifRegs->r3 = _vifRow[3]; //QueryPerformanceCounter(&lfinal); //((LARGE_INTEGER*)g_nCounters)->QuadPart += lfinal.QuadPart - lbase.QuadPart; } else { int incdest; // Assigning the normal upack function, the part type is assigned later func = vif->usn ? ft->funcU : ft->funcS; funcP = vif->usn ? ft->funcUpart : ft->funcSpart; incdest = ((vifRegs->cycle.cl - vifRegs->cycle.wl)<<2) + 4; //SysPrintf("slow vif\n"); //if(skipped > 0) skipped = 0; vif->tag.addr += (size / (ft->gsize*vifRegs->cycle.wl)) * ((vifRegs->cycle.cl - vifRegs->cycle.wl)*16); while (size >= ft->gsize && vifRegs->num > 0) { funcP( dest, (u32*)cdata, ft->qsize); cdata += ft->gsize; size -= ft->gsize; vifRegs->num--; //SysPrintf("%d transferred, remaining %d, vifnum %d\n", ft->gsize, size, vifRegs->num); ++vif->cl; if (vif->cl == vifRegs->cycle.wl) { dest += incdest; vif->cl = 0; } else { dest += 4; } } // have to update _vifRow[0] = _vifRegs->r0; _vifRow[1] = _vifRegs->r1; _vifRow[2] = _vifRegs->r2; _vifRow[3] = _vifRegs->r3; } // used for debugging vif // { // int i, j; // u32* curdest = olddest; // FILE* ftemp = fopen("temp.txt", "a+"); // fprintf(ftemp, "%x %x %x\n", s_count, size, vif->tag.addr); // fprintf(ftemp, "%x %x %x\n", vifRegs->code>>24, vifRegs->mode, *(u32*)&vifRegs->cycle); // fprintf(ftemp, "row: %x %x %x %x\n", _vifRow[0], _vifRow[1], _vifRow[2], _vifRow[3]); // //fprintf(ftemp, "row2: %x %x %x %x\n", _vifRegs->r0, _vifRegs->r1, _vifRegs->r2, _vifRegs->r3); // // for(i = 0; i < memsize; ) { // for(j = 0; j <= ((vifRegs->code>>26)&3); ++j) { // fprintf(ftemp, "%x ", curdest[j]); // } // fprintf(ftemp, "\n"); // curdest += 4*vifRegs->cycle.cl; // i += j*ft->dsize; // } // fclose(ftemp); // } // s_count++; if( size >= ft->dsize && vifRegs->num > 0) { #ifdef VIF_LOG VIF_LOG("warning, end with size = %d\n", size); #endif // SSE doesn't handle such small data ft = &VIFfuncTable[ unpackType ]; func = vif->usn ? ft->funcU : ft->funcS; funcP = vif->usn ? ft->funcUpart : ft->funcSpart; #ifdef VIFUNPACKDEBUG SysPrintf("end with size %x dsize = %x\n", size, ft->dsize); #endif while (size >= ft->dsize) { /* unpack one qword */ funcP(dest, (u32*)cdata, 1); dest += 1; size -= ft->dsize; } #ifdef VIFUNPACKDEBUG SysPrintf("leftover done, size %d, vifnum %d, addr %x\n", size, vifRegs->num, vif->tag.addr); #endif } } else if (vifRegs->cycle.cl < vifRegs->cycle.wl) { /* filling write */ u32 dummy[8]; #ifdef VIF_LOG VIF_LOG("*PCSX2*: filling write\n"); #endif ft = &VIFfuncTable[ unpackType ]; func = vif->usn ? ft->funcU : ft->funcS; funcP = vif->usn ? ft->funcUpart : ft->funcSpart; #ifdef VIFUNPACKDEBUG SysPrintf("filling write %d cl %d, wl %d\n", vifRegs->num, vifRegs->cycle.cl, vifRegs->cycle.wl); #endif while (size >= ft->gsize || vifRegs->num > 0) { if (vif->cl == vifRegs->cycle.wl) { vif->cl = 0; } // if (vif->cl < vifRegs->cycle.cl) { /* unpack one qword */ funcP( dest, (u32*)cdata, ft->qsize); cdata += ft->gsize; size -= ft->gsize; vif->cl++; vifRegs->num--; if (vif->cl == vifRegs->cycle.wl) { vif->cl = 0; } } else { funcP( dest, (u32*)dummy, ft->qsize); //cdata += ft->gsize; //size -= ft->gsize; vif->tag.addr += 16; vifRegs->num--; ++vif->cl; } dest += 4; //++vif->wl; } } if(vifRegs->num == 0 && size > 3) SysPrintf("Size = %x, Vifnum = 0!\n", size); } static void vuExecMicro( u32 addr, const unsigned int VIFdmanum ) { int _cycles; VURegs * VU; //void (*_vuExecMicro)(); // MessageBox(NULL, "3d doesn't work\n", "Query", MB_OK); // return; if (VIFdmanum == 0) { //_vuExecMicro = Cpu->ExecuteVU0Block; VU = &VU0; vif0FLUSH(); } else { //_vuExecMicro = Cpu->ExecuteVU1Block; VU = &VU1; vif1FLUSH(); } VU->vifRegs->itop = VU->vifRegs->itops; if (VIFdmanum == 1) { /* in case we're handling a VIF1 execMicro set the top with the tops value */ VU->vifRegs->top = VU->vifRegs->tops; /* is DBF flag set in VIF_STAT? */ if (VU->vifRegs->stat & 0x80) { /* it is, so set tops with base + ofst and clear stat DBF flag */ VU->vifRegs->tops = VU->vifRegs->base; VU->vifRegs->stat &= ~0x80; } else { /* it is not, so set tops with base and set the stat DBF flag */ VU->vifRegs->tops = VU->vifRegs->base + VU->vifRegs->ofst; VU->vifRegs->stat |= 0x80; } } if (VIFdmanum == 0) { _cycles = VU0.cycle; vu0ExecMicro(addr); // too much delay //g_vifCycles+= (VU0.cycle - _cycles)*BIAS; } else { _cycles = VU1.cycle; vu1ExecMicro(addr); // too much delay //g_vifCycles+= (VU1.cycle - _cycles)*BIAS; } } void vif0Init() { u32 i; extern u8 s_maskwrite[256]; for(i = 0; i < 256; ++i ) { s_maskwrite[i] = ((i&3)==3)||((i&0xc)==0xc)||((i&0x30)==0x30)||((i&0xc0)==0xc0); } SetNewMask(g_vif0Masks, g_vif0HasMask3, 0, 0xffffffff); } __inline void vif0FLUSH() { int _cycles; _cycles = VU0.cycle; vu0Finish(); g_vifCycles+= (VU0.cycle - _cycles)*BIAS; } __inline void vif0UNPACK(u32 *data) { int vifNum; int vl, vn; int len; if(vif0Regs->cycle.wl == 0 && vif0Regs->cycle.wl < vif0Regs->cycle.cl){ SysPrintf("Vif0 CL %d, WL %d\n", vif0Regs->cycle.cl, vif0Regs->cycle.wl); vif0.cmd &= ~0x7f; return; } vif0FLUSH(); vl = (vif0.cmd ) & 0x3; vn = (vif0.cmd >> 2) & 0x3; vif0.tag.addr = (data[0] & 0x3ff) << 4; vif0.usn = (data[0] >> 14) & 0x1; vifNum = (data[0] >> 16) & 0xff; if ( vifNum == 0 ) vifNum = 256; vif0Regs->num = vifNum; if ( vif0Regs->cycle.wl <= vif0Regs->cycle.cl ) { len = ((( 32 >> vl ) * ( vn + 1 )) * vifNum + 31) >> 5; } else { int n = vif0Regs->cycle.cl * (vifNum / vif0Regs->cycle.wl) + _limit( vifNum % vif0Regs->cycle.wl, vif0Regs->cycle.cl ); len = ( ((( 32 >> vl ) * ( vn + 1 )) * n) + 31 ) >> 5; } vif0.wl = 0; vif0.cl = 0; vif0.tag.cmd = vif0.cmd; vif0.tag.size = len; vif0Regs->offset = 0; } __inline void _vif0mpgTransfer(u32 addr, u32 *data, int size) { /* SysPrintf("_vif0mpgTransfer addr=%x; size=%x\n", addr, size); { FILE *f = fopen("vu1.raw", "wb"); fwrite(data, 1, size*4, f); fclose(f); }*/ if (memcmp(VU0.Micro + addr, data, size << 2)) { memcpy_amd(VU0.Micro + addr, data, size << 2); Cpu->ClearVU0(addr, size); } } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Vif1 Data Transfer Table //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int (*Vif0TransTLB[128])(u32 *data, int size) = { Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x7*/ Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0xF*/ Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x17*/ Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x1F*/ Vif0TransSTMask , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x27*/ Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x2F*/ Vif0TransSTRow , Vif0TransSTCol , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x37*/ Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x3F*/ Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x47*/ Vif0TransNull , Vif0TransNull , Vif0TransMPG , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x4F*/ Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x57*/ Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x5F*/ Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransNull , /*0x67*/ Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , /*0x6F*/ Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransNull , /*0x77*/ Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransNull , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack /*0x7F*/ }; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Vif1 CMD Table //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void (*Vif0CMDTLB[75])() = { Vif0CMDNop , Vif0CMDSTCycl , Vif0CMDNull , Vif0CMDNull , Vif0CMDITop , Vif0CMDSTMod , Vif0CMDNull, Vif0CMDMark , /*0x7*/ Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0xF*/ Vif0CMDFlushE , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull, Vif0CMDMSCALF, Vif0CMDMSCALF, Vif0CMDNull , Vif0CMDMSCNT, /*0x17*/ Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x1F*/ Vif0CMDSTMask , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x27*/ Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x2F*/ Vif0CMDSTRowCol, Vif0CMDSTRowCol, Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x37*/ Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x3F*/ Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x47*/ Vif0CMDNull , Vif0CMDNull , Vif0CMDMPGTransfer }; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Vif1 Data Transfer Commands //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static int Vif0TransNull(u32 *data, int size){ // Shouldnt go here SysPrintf("VIF0 Shouldnt go here CMD = %x\n", vif0Regs->code); vif0.cmd = 0; return 0; } static int Vif0TransSTMask(u32 *data, int size){ // STMASK SetNewMask(g_vif0Masks, g_vif0HasMask3, data[0], vif0Regs->mask); vif0Regs->mask = data[0]; #ifdef VIF_LOG VIF_LOG("STMASK == %x\n", vif0Regs->mask); #endif vif0.tag.size = 0; vif0.cmd = 0; return 1; } static int Vif0TransSTRow(u32 *data, int size){ // STROW int ret; u32* pmem = &vif0Regs->r0+(vif0.tag.addr<<2); u32* pmem2 = g_vifRow0+vif0.tag.addr; assert( vif0.tag.addr < 4 ); ret = min(4-vif0.tag.addr, size); assert( ret > 0 ); switch(ret) { case 4: pmem[12] = data[3]; pmem2[3] = data[3]; case 3: pmem[8] = data[2]; pmem2[2] = data[2]; case 2: pmem[4] = data[1]; pmem2[1] = data[1]; case 1: pmem[0] = data[0]; pmem2[0] = data[0]; break; default: __assume(0); } vif0.tag.addr += ret; vif0.tag.size -= ret; if(vif0.tag.size == 0) vif0.cmd = 0; return ret; } static int Vif0TransSTCol(u32 *data, int size){ // STCOL int ret; u32* pmem = &vif0Regs->c0+(vif0.tag.addr<<2); u32* pmem2 = g_vifCol0+vif0.tag.addr; ret = min(4-vif0.tag.addr, size); switch(ret) { case 4: pmem[12] = data[3]; pmem2[3] = data[3]; case 3: pmem[8] = data[2]; pmem2[2] = data[2]; case 2: pmem[4] = data[1]; pmem2[1] = data[1]; case 1: pmem[0] = data[0]; pmem2[0] = data[0]; break; default: __assume(0); } vif0.tag.addr += ret; vif0.tag.size -= ret; if(vif0.tag.size == 0) vif0.cmd = 0; return ret; } static int Vif0TransMPG(u32 *data, int size){ // MPG if (size < vif0.tag.size) { _vif0mpgTransfer(vif0.tag.addr, data, size); vif0.tag.addr += size << 2; vif0.tag.size -= size; return size; } else { int ret; _vif0mpgTransfer(vif0.tag.addr, data, vif0.tag.size); ret = vif0.tag.size; vif0.tag.size = 0; vif0.cmd = 0; return ret; } } static int Vif0TransUnpack(u32 *data, int size){ // UNPACK if (size < vif0.tag.size) { /* size is less that the total size, transfer is 'in pieces' */ VIFunpack(data, &vif0.tag, size, VIF0dmanum); // g_vifCycles+= size >> 1; //vif0.tag.addr += size << 2; vif0.tag.size -= size; return size; } else { int ret; /* we got all the data, transfer it fully */ VIFunpack(data, &vif0.tag, vif0.tag.size, VIF0dmanum); //g_vifCycles+= vif0.tag.size >> 1; ret = vif0.tag.size; vif0.tag.size = 0; vif0.cmd = 0; return ret; } } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Vif0 CMD Base Commands //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static void Vif0CMDNop(){ // NOP vif0.cmd &= ~0x7f; } static void Vif0CMDSTCycl(){ // STCYCL vif0Regs->cycle.cl = (u8)vif0Regs->code; vif0Regs->cycle.wl = (u8)(vif0Regs->code >> 8); vif0.cmd &= ~0x7f; } static void Vif0CMDITop(){ // ITOP vif0Regs->itops = vif0Regs->code & 0x3ff; vif0.cmd &= ~0x7f; } static void Vif0CMDSTMod(){ // STMOD vif0Regs->mode = vif0Regs->code & 0x3; vif0.cmd &= ~0x7f; } static void Vif0CMDMark(){ // MARK vif0Regs->mark = (u16)vif0Regs->code; vif0Regs->stat |= VIF0_STAT_MRK; vif0.cmd &= ~0x7f; } static void Vif0CMDFlushE(){ // FLUSHE vif0FLUSH(); vif0.cmd &= ~0x7f; } static void Vif0CMDMSCALF(){ //MSCAL/F vuExecMicro( (u16)(vif0Regs->code) << 3, VIF0dmanum ); vif0.cmd &= ~0x7f; } static void Vif0CMDMSCNT(){ // MSCNT vuExecMicro( -1, VIF0dmanum ); vif0.cmd &= ~0x7f; } static void Vif0CMDSTMask(){ // STMASK vif0.tag.size = 1; } static void Vif0CMDSTRowCol(){// STROW / STCOL vif0.tag.addr = 0; vif0.tag.size = 4; } static void Vif0CMDMPGTransfer(){ // MPG int vifNum; vif0FLUSH(); vifNum = (u8)(vif0Regs->code >> 16); if (vifNum == 0) vifNum = 256; vif0.tag.addr = (u16)(vif0Regs->code) << 3; vif0.tag.size = vifNum * 2; } static void Vif0CMDNull(){ // invalid opcode // if ME1, then force the vif to interrupt vif0.cmd = (vif0Regs->err&0x40)?0x80:0; if ((vif0Regs->err & 0x6) == 0) { //Ignore vifcode and tag mismatch error SysPrintf( "UNKNOWN VifCmd: %x\n", vif0.cmd ); vif0Regs->stat |= 1 << 13; } } int VIF0transfer(u32 *data, int size, int istag) { int ret; int transferred=vif0.vifstalled ? vif0.irqoffset : 0; // irqoffset necessary to add up the right qws, or else will spin (spiderman) //vif0.irqoffset = 0; #ifdef VIF_LOG VIF_LOG( "VIF0transfer: size %x (vif0.cmd %x)\n", size, vif0.cmd ); #endif //return 0; if(vif0.savedtag){ vif0.cmd = vif0.savedtag; vif0.savedtag = 0; } //vif0.irq = 0; while (size > 0) { if((vif0.cmd & 0x70) == 0x50 && istag) { vif0.savedtag = vif0.cmd; vif0.cmd = 0; continue; } if((vif0.cmd & 0x70) == 0x40 && istag && size < 2) { vif0.savedtag = vif0.cmd; vif0.cmd = 0; continue; } if (vif0.cmd & 0x7f) { //vif0Regs->stat |= VIF0_STAT_VPS_T; ret = Vif0TransTLB[(vif0.cmd & 0x7f)](data, size); data+= ret; size-= ret; transferred+= ret; //vif0Regs->stat &= ~VIF0_STAT_VPS_T; continue; } vif0Regs->stat &= ~VIF0_STAT_VPS_W; // if interrupt and new cmd is NOT MARK if(vif0.irq && ((vif0Regs->code >> 24) & 0x7f) != 0x7 && vif0.tag.size == 0) { if(vif0.tag.size > 0) SysPrintf("Stall when vif0 tagsize %x code %x\n", vif0.tag.size, vif0.cmd); break; } vif0.cmd = (data[0] >> 24); vif0Regs->code = data[0]; #ifdef VIF_LOG VIF_LOG( "VIFtransfer: cmd %x, num %x, imm %x, size %x\n", vif0.cmd, (data[0] >> 16) & 0xff, data[0] & 0xffff, size ); #endif //vif0Regs->stat |= VIF0_STAT_VPS_D; if ((vif0.cmd & 0x60) == 0x60) { vif0UNPACK(data); } else { //vif0CMD(data, size); Vif0CMDTLB[(vif0.cmd & 0x7f)](); } //vif0Regs->stat &= ~VIF0_STAT_VPS_D; if(vif0.tag.size > 0) vif0Regs->stat |= VIF0_STAT_VPS_W; ++data; --size; ++transferred; if ((vif0.cmd & 0x80) && !(vif0Regs->err & 0x1) && ((vif0Regs->code >> 24) & 0x7f) != 0x7 ) { //i bit on vifcode and not masked by VIF0_ERR #ifdef VIF_LOG VIF_LOG( "Interrupt on VIFcmd: %x (INTC_MASK = %x)\n", vif0.cmd, psHu32(INTC_MASK) ); #endif //vif0Regs->stat|= VIF0_STAT_VIS; ++vif0.irq; vif0.cmd &= 0x7f; } if(vif0.irq && ((vif0Regs->code >> 24) & 0x7f) != 0x7 && vif0.tag.size == 0) { break; } } // use tag.size because some game doesn't like .cmd //if( !vif0.cmd ) if( !vif0.tag.size ) vif0Regs->stat &= ~VIF0_STAT_VPS_W; if (vif0.irq > 0) { if( istag ) { return -2; } // spiderman doesn't break on qw boundaries vif0.irqoffset = transferred%4; // cannot lose the offset transferred = transferred >> 2; vif0ch->madr+= (transferred << 4); vif0ch->qwc-= transferred; //SysPrintf("Stall on vif0, FromSPR = %x, Vif0MADR = %x Sif0MADR = %x STADR = %x\n", psHu32(0x1000d010), vif0ch->madr, psHu32(0x1000c010), psHu32(DMAC_STADR)); return -2; } if( !istag ) { transferred = transferred >> 2; vif0ch->madr+= (transferred << 4); vif0ch->qwc-= transferred; } return 0; } int _VIF0chain() { u32 *pMem; u32 qwc = vif0ch->qwc; u32 ret; if (vif0ch->qwc == 0 && vif0.irqoffset != 0) SysPrintf("Narf0 QWC %x, offset %x\n", vif0ch->qwc, vif0.irqoffset); if (vif0ch->qwc == 0) return 0; pMem = (u32*)dmaGetAddr(vif0ch->madr); if (pMem == NULL) return -1; if( vif0.vifstalled ) { ret = VIF0transfer(pMem+vif0.irqoffset, vif0ch->qwc*4-vif0.irqoffset, 0); } else { ret = VIF0transfer(pMem, vif0ch->qwc*4, 0); } /*vif0ch->madr+= (vif0ch->qwc << 4); vif0ch->qwc-= qwc;*/ g_vifCycles+= (qwc-vif0ch->qwc)*BIAS; /* guessing */ return ret; } int _chainVIF0() { int id; u32 *ptag; //int done=0; int ret; ptag = (u32*)dmaGetAddr(vif0ch->tadr); //Set memory pointer to TADR if (ptag == NULL) { //Is ptag empty? SysPrintf("Vif0 Tag BUSERR\n"); vif0ch->chcr = ( vif0ch->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 psHu32(DMAC_STAT)|= 1<<15; //If yes, set BEIS (BUSERR) in DMAC_STAT register return -1; //Return -1 as an error has occurred } id = (ptag[0] >> 28) & 0x7; //ID for DmaChain copied from bit 28 of the tag vif0ch->qwc = (u16)ptag[0]; //QWC set to lower 16bits of the tag vif0ch->madr = ptag[1]; //MADR = ADDR field g_vifCycles+=1; // Add 1 g_vifCycles from the QW read for the tag #ifdef VIF_LOG VIF_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx\n", ptag[1], ptag[0], vif0ch->qwc, id, vif0ch->madr, vif0ch->tadr); #endif vif0ch->chcr = ( vif0ch->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 // Transfer dma tag if tte is set vif0.done |= hwDmacSrcChainWithStack(vif0ch, id); if (vif0ch->chcr & 0x40) { ret = VIF0transfer(ptag+2, 2, 1); //Transfer Tag if (ret == -1) return -1; //There has been an error if (ret == -2) { vif0.vifstalled = 1; return vif0.done; //IRQ set by VIFTransfer } } #ifdef VIF_LOG VIF_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx\n", ptag[1], ptag[0], vif0ch->qwc, id, vif0ch->madr, vif0ch->tadr); #endif //done |= hwDmacSrcChainWithStack(vif0ch, id); ret = _VIF0chain(); //Transfers the data set by the switch if (ret == -1) { return -1; } //There's been an error if (ret == -2) { //IRQ has been set by VifTransfer vif0.vifstalled = 1; return vif0.done; } //if(id == 7)vif0ch->tadr = vif0ch->madr; vif0.vifstalled = 0; if ((vif0ch->chcr & 0x80) && (ptag[0] >> 31)) { //Check TIE bit of CHCR and IRQ bit of tag #ifdef VIF_LOG VIF_LOG( "dmaIrq Set\n" ); #endif //SysPrintf("VIF0 TIE\n"); //SysPrintf( "VIF0dmaIrq Set\n" ); //vif0ch->qwc = 0; //vif0Regs->stat|= VIF0_STAT_VIS; //Set the Tag Interrupt flag of VIF0_STAT vif0.done = 1; return vif0.done; //End Transfer } return vif0.done; //Return Done } static int _vif0Interrupt() { int ret; #ifdef VIF_LOG VIF_LOG("vif0Interrupt: %8.8x\n", cpuRegs.cycle); #endif if(vif0.vifstalled == 1) { if(vif0.irq) { vif0Regs->stat|= VIF0_STAT_INT; hwIntcIrq(VIF0intc); --vif0.irq; } vif0Regs->stat&= ~0xF000000; // FQC=0 if(vif0.done == 1 && vif0ch->qwc == 0 && vif0.irqoffset == 0) { //SysPrintf("Vif0 Stall, done = 1 qwc = 0 irqoffset = %x, tell ref\n", vif0.irqoffset); vif0.vifstalled = 0; } else return 1; } if (vif0ch->chcr & 0x4 && vif0.done == 0 && vif0.vifstalled == 0) { if( !(psHu32(DMAC_CTRL) & 0x1) ) { SysPrintf("vif0 dma masked\n"); return 0; } g_vifCycles = 0; if(vif0ch->qwc > 0) _VIF0chain(); ret = _chainVIF0(); INT(0, g_vifCycles); return 0; //if(ret!=2) /*else*/ //return 1; } vif0ch->chcr &= ~0x100; hwDmacIrq(DMAC_VIF0); vif0Regs->stat&= ~0xF000000; // FQC=0 return 1; } int vif0Interrupt() { int ret; ret = _vif0Interrupt(); //FreezeXMMRegs(0); //FreezeMMXRegs(0); return ret; } void _dmaVIF0() { #ifdef VIF_LOG VIF_LOG("dmaVIF0 chcr = %lx, madr = %lx, qwc = %lx\n" " tadr = %lx, asr0 = %lx, asr1 = %lx\n", vif0ch->chcr, vif0ch->madr, vif0ch->qwc, vif0ch->tadr, vif0ch->asr0, vif0ch->asr1 ); #endif /* Check if there is a pending irq */ /*if (vif0.irq > 0) { vif0.irq--; hwIntcIrq(VIF0intc); return; }*/ // if(vif0ch->qwc > 0) { // _VIF0chain(); // INT(0, g_vifCycles); // } g_vifCycles = 0; vif0Regs->stat|= 0x8000000; // FQC=8 if (!(vif0ch->chcr & 0x4) || vif0ch->qwc > 0) { // Normal Mode if(_VIF0chain() == -2) { SysPrintf("Stall on normal\n"); vif0.vifstalled = 1; return; } vif0.done = 1; INT(0, g_vifCycles); return; } /* if (_VIF0chain() != 0) { INT(0, g_vifCycles); return; }*/ // Chain Mode vif0.done = 0; _vif0Interrupt(); INT(0, g_vifCycles); } void dmaVIF0() { _dmaVIF0(); FreezeXMMRegs(0); FreezeMMXRegs(0); } void vif0Write32(u32 mem, u32 value) { if (mem == 0x10003830) { // MARK #ifdef VIF_LOG VIF_LOG("VIF0_MARK write32 0x%8.8x\n", value); #endif /* Clear mark flag in VIF0_STAT and set mark with 'value' */ vif0Regs->stat&= ~VIF0_STAT_MRK; vif0Regs->mark = value; } else if (mem == 0x10003810) { // FBRST #ifdef VIF_LOG VIF_LOG("VIF0_FBRST write32 0x%8.8x\n", value); #endif if (value & 0x1) { /* Reset VIF */ //SysPrintf("Vif0 Reset\n"); memset(&vif0, 0, sizeof(vif0)); vif0ch->qwc = 0; //? psHu64(0x10004000) = 0; psHu64(0x10004008) = 0; vif0.done = 1; vif0Regs->err = 0; vif0Regs->stat&= ~0xF000000; // FQC=0 } if (value & 0x2) { /* Force Break the VIF */ /* I guess we should stop the VIF dma here but not 100% sure (linuz) */ vif0Regs->stat |= VIF0_STAT_VFS; SysPrintf("vif0 force break\n"); } if (value & 0x4) { /* Stop VIF */ /* Not completly sure about this, can't remember what game used this, but 'draining' the VIF helped it, instead of just stoppin the VIF (linuz) */ vif0Regs->stat |= VIF0_STAT_VSS; //SysPrintf("Vif0 Stop\n"); //dmaVIF0(); // Drain the VIF --- VIF Stops as not to outstrip dma source (refraction) //FreezeXMMRegs(0); } if (value & 0x8) { int cancel = 0; /* Cancel stall, first check if there is a stall to cancel, and then clear VIF0_STAT VSS|VFS|VIS|INT|ER0|ER1 bits */ if (vif0Regs->stat & (VIF0_STAT_INT|VIF0_STAT_VSS|VIF0_STAT_VIS|VIF0_STAT_VFS)) { cancel = 1; } vif0Regs->stat &= ~(VIF0_STAT_VSS | VIF0_STAT_VFS | VIF0_STAT_VIS | VIF0_STAT_INT | VIF0_STAT_ER0 | VIF0_STAT_ER1); if (cancel) { //SysPrintf("VIF0 Stall Resume\n"); if( vif0.vifstalled ) { // loop necessary for spiderman if ( _VIF0chain() != -2 ) vif0.vifstalled = 0; FreezeXMMRegs(0); FreezeMMXRegs(0); INT(0, g_vifCycles); // Gets the timing right - Flatout } } } } else if (mem == 0x10003820) { // ERR #ifdef VIF_LOG VIF_LOG("VIF0_ERR write32 0x%8.8x\n", value); #endif /* Set VIF0_ERR with 'value' */ vif0Regs->err = value; } else{ SysPrintf("Unknown Vif0 write to %x\n", mem); if( mem >= 0x10003900 && mem < 0x10003980 ) { assert( (mem&0xf) == 0 ); if( mem < 0x10003940 ) g_vifRow0[(mem>>4)&3] = value; else g_vifCol0[(mem>>4)&3] = value; } else psHu32(mem) = value; } /* Other registers are read-only so do nothing for them */ } void vif0Reset() { /* Reset the whole VIF, meaning the internal pcsx2 vars and all the registers */ memset(&vif0, 0, sizeof(vif0)); memset(vif0Regs, 0, sizeof(vif0Regs)); SetNewMask(g_vif0Masks, g_vif0HasMask3, 0, 0xffffffff); psHu64(0x10004000) = 0; psHu64(0x10004008) = 0; vif0.done = 1; vif0Regs->stat&= ~0xF000000; // FQC=0 FreezeXMMRegs(0); FreezeMMXRegs(0); } int vif0Freeze(gzFile f, int Mode) { gzfreeze(&vif0, sizeof(vif0)); if (Mode == 0) SetNewMask(g_vif0Masks, g_vif0HasMask3, vif0Regs->mask, ~vif0Regs->mask); return 0; } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// void vif1Init() { SetNewMask(g_vif1Masks, g_vif1HasMask3, 0, 0xffffffff); } __inline void vif1FLUSH() { int _cycles; _cycles = VU1.cycle; if( VU0.VI[REG_VPU_STAT].UL & 0x100 ) { FreezeXMMRegs(1); do { Cpu->ExecuteVU1Block(); } while(VU0.VI[REG_VPU_STAT].UL & 0x100); // FreezeXMMRegs(0); // FreezeMMXRegs(0); g_vifCycles+= (VU1.cycle - _cycles)*BIAS; } } __inline void vif1UNPACK(u32 *data) { int vifNum; int vl, vn; int len; if(vif1Regs->cycle.wl == 0 && vif1Regs->cycle.wl < vif1Regs->cycle.cl){ SysPrintf("Vif1 CL %d, WL %d\n", vif1Regs->cycle.cl, vif1Regs->cycle.wl); vif1.cmd &= ~0x7f; return; } vif1FLUSH(); vl = (vif1.cmd ) & 0x3; vn = (vif1.cmd >> 2) & 0x3; vif1.tag.addr = (data[0] & 0x3ff); vif1.usn = (data[0] >> 14) & 0x1; vifNum = (data[0] >> 16) & 0xff; if ( vifNum == 0 ) vifNum = 256; vif1Regs->num = vifNum; if ( vif1Regs->cycle.wl <= vif1Regs->cycle.cl ) { len = ((( 32 >> vl ) * ( vn + 1 )) * vifNum + 31) >> 5; } else { int n = vif1Regs->cycle.cl * (vifNum / vif1Regs->cycle.wl) + _limit( vifNum % vif1Regs->cycle.wl, vif1Regs->cycle.cl ); len = ( ((( 32 >> vl ) * ( vn + 1 )) * n) + 31 ) >> 5; } if ( ( data[0] >> 15) & 0x1 ) { vif1.tag.addr += vif1Regs->tops; } vif1.wl = 0; vif1.cl = 0; vif1.tag.addr <<= 4; vif1.tag.addr &= 0x3fff; vif1.tag.cmd = vif1.cmd; vif1.tag.size = len; vif1Regs->offset = 0; } __inline void _vif1mpgTransfer(u32 addr, u32 *data, int size) { /* SysPrintf("_vif1mpgTransfer addr=%x; size=%x\n", addr, size); { FILE *f = fopen("vu1.raw", "wb"); fwrite(data, 1, size*4, f); fclose(f); }*/ if (memcmp(VU1.Micro + addr, data, size << 2)) { memcpy_amd(VU1.Micro + addr, data, size << 2); Cpu->ClearVU1(addr, size); } } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Vif1 Data Transfer Table //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int (*Vif1TransTLB[128])(u32 *data, int size) = { Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x7*/ Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0xF*/ Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x17*/ Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x1F*/ Vif1TransSTMask , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x27*/ Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x2F*/ Vif1TransSTRow , Vif1TransSTCol , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x37*/ Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x3F*/ Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x47*/ Vif1TransNull , Vif1TransNull , Vif1TransMPG , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x4F*/ Vif1TransDirectHL, Vif1TransDirectHL, Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x57*/ Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x5F*/ Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransNull , /*0x67*/ Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , /*0x6F*/ Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransNull , /*0x77*/ Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransNull , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack /*0x7F*/ }; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Vif1 CMD Table //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void (*Vif1CMDTLB[82])() = { Vif1CMDNop , Vif1CMDSTCycl , Vif1CMDOffset , Vif1CMDBase , Vif1CMDITop , Vif1CMDSTMod , Vif1CMDMskPath3, Vif1CMDMark , /*0x7*/ Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0xF*/ Vif1CMDFlush , Vif1CMDFlush , Vif1CMDNull , Vif1CMDFlush, Vif1CMDMSCALF, Vif1CMDMSCALF, Vif1CMDNull , Vif1CMDMSCNT, /*0x17*/ Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x1F*/ Vif1CMDSTMask , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x27*/ Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x2F*/ Vif1CMDSTRowCol, Vif1CMDSTRowCol, Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x37*/ Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x3F*/ Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x47*/ Vif1CMDNull , Vif1CMDNull , Vif1CMDMPGTransfer, Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x4F*/ Vif1CMDDirectHL, Vif1CMDDirectHL }; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Vif1 Data Transfer Commands //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static int Vif1TransNull(u32 *data, int size){ // Shouldnt go here SysPrintf("Shouldnt go here CMD = %x\n", vif1Regs->code); vif1.cmd = 0; return 0; } static int Vif1TransSTMask(u32 *data, int size){ // STMASK SetNewMask(g_vif1Masks, g_vif1HasMask3, data[0], vif1Regs->mask); vif1Regs->mask = data[0]; #ifdef VIF_LOG VIF_LOG("STMASK == %x\n", vif1Regs->mask); #endif vif1.tag.size = 0; vif1.cmd = 0; return 1; } static int Vif1TransSTRow(u32 *data, int size){ int ret; u32* pmem = &vif1Regs->r0+(vif1.tag.addr<<2); u32* pmem2 = g_vifRow1+vif1.tag.addr; assert( vif1.tag.addr < 4 ); ret = min(4-vif1.tag.addr, size); assert( ret > 0 ); switch(ret) { case 4: pmem[12] = data[3]; pmem2[3] = data[3]; case 3: pmem[8] = data[2]; pmem2[2] = data[2]; case 2: pmem[4] = data[1]; pmem2[1] = data[1]; case 1: pmem[0] = data[0]; pmem2[0] = data[0]; break; default: __assume(0); } vif1.tag.addr += ret; vif1.tag.size -= ret; if(vif1.tag.size == 0) vif1.cmd = 0; return ret; } static int Vif1TransSTCol(u32 *data, int size){ int ret; u32* pmem = &vif1Regs->c0+(vif1.tag.addr<<2); u32* pmem2 = g_vifCol1+vif1.tag.addr; ret = min(4-vif1.tag.addr, size); switch(ret) { case 4: pmem[12] = data[3]; pmem2[3] = data[3]; case 3: pmem[8] = data[2]; pmem2[2] = data[2]; case 2: pmem[4] = data[1]; pmem2[1] = data[1]; case 1: pmem[0] = data[0]; pmem2[0] = data[0]; break; default: __assume(0); } vif1.tag.addr += ret; vif1.tag.size -= ret; if(vif1.tag.size == 0) vif1.cmd = 0; return ret; } static int Vif1TransMPG(u32 *data, int size){ if (size < vif1.tag.size) { _vif1mpgTransfer(vif1.tag.addr, data, size); vif1.tag.addr += size << 2; vif1.tag.size -= size; return size; } else { int ret; _vif1mpgTransfer(vif1.tag.addr, data, vif1.tag.size); ret = vif1.tag.size; vif1.tag.size = 0; vif1.cmd = 0; return ret; } } static int Vif1TransDirectHL(u32 *data, int size){ int ret; if (size < vif1.tag.size) { vif1.tag.size-= size; ret = size; } else { ret = vif1.tag.size; vif1.tag.size = 0; vif1.cmd = 0; } if( CHECK_MULTIGS ) { u8* gsmem = GSRingBufCopy(data, ret<<2, GS_RINGTYPE_P2); if( gsmem != NULL ) { memcpy_amd(gsmem, data, ret<<2); GSRINGBUF_DONECOPY(gsmem, ret<<2); GSgifTransferDummy(1, data, ret>>2); } if( !CHECK_DUALCORE ) SetEvent(g_hGsEvent);//GS_SETEVENT(); } else { FreezeMMXRegs(1); FreezeXMMRegs(1); GSGIFTRANSFER2(data, (ret >> 2)); } return ret; } static int Vif1TransUnpack(u32 *data, int size){ if (size < vif1.tag.size) { /* size is less that the total size, transfer is 'in pieces' */ VIFunpack(data, &vif1.tag, size, VIF1dmanum); // g_vifCycles+= size >> 1; //vif1.tag.addr += size << 2; vif1.tag.size -= size; return size; } else { int ret; /* we got all the data, transfer it fully */ VIFunpack(data, &vif1.tag, vif1.tag.size, VIF1dmanum); //g_vifCycles+= vif1.tag.size >> 1; ret = vif1.tag.size; vif1.tag.size = 0; vif1.cmd = 0; return ret; } } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Vif1 CMD Base Commands //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static void Vif1CMDNop(){ // NOP vif1.cmd &= ~0x7f; } static void Vif1CMDSTCycl(){ // STCYCL vif1Regs->cycle.cl = (u8)vif1Regs->code; vif1Regs->cycle.wl = (u8)(vif1Regs->code >> 8); vif1.cmd &= ~0x7f; } static void Vif1CMDOffset(){ // OFFSET vif1Regs->ofst = vif1Regs->code & 0x3ff; vif1Regs->stat &= ~0x80; vif1Regs->tops = vif1Regs->base; vif1.cmd &= ~0x7f; } static void Vif1CMDBase(){ // BASE vif1Regs->base = vif1Regs->code & 0x3ff; vif1.cmd &= ~0x7f; } static void Vif1CMDITop(){ // ITOP vif1Regs->itops = vif1Regs->code & 0x3ff; vif1.cmd &= ~0x7f; } static void Vif1CMDSTMod(){ // STMOD vif1Regs->mode = vif1Regs->code & 0x3; vif1.cmd &= ~0x7f; } static void Vif1CMDMskPath3(){ // MSKPATH3 vif1Regs->mskpath3 = (vif1Regs->code >> 15) & 0x1; if ( vif1Regs->mskpath3 ) { if(gif->qwc) _GIFchain(); // Finish the transfer first psHu32(GIF_STAT) |= 0x2; } else { psHu32(GIF_STAT) &= ~0x2; if(gif->qwc) _GIFchain(); // Finish the transfer first } vif1.cmd &= ~0x7f; } static void Vif1CMDMark(){ // MARK vif1Regs->mark = (u16)vif1Regs->code; vif1Regs->stat |= VIF1_STAT_MRK; vif1.cmd &= ~0x7f; } static void Vif1CMDFlush(){ // FLUSH/E/A vif1FLUSH(); vif1.cmd &= ~0x7f; } static void Vif1CMDMSCALF(){ //MSCAL/F vuExecMicro( (u16)(vif1Regs->code) << 3, VIF1dmanum ); vif1.cmd &= ~0x7f; } static void Vif1CMDMSCNT(){ // MSCNT vuExecMicro( -1, VIF1dmanum ); vif1.cmd &= ~0x7f; } static void Vif1CMDSTMask(){ // STMASK vif1.tag.size = 1; } static void Vif1CMDSTRowCol(){// STROW / STCOL vif1.tag.addr = 0; vif1.tag.size = 4; } static void Vif1CMDMPGTransfer(){ // MPG int vifNum; vif1FLUSH(); vifNum = (u8)(vif1Regs->code >> 16); if (vifNum == 0) vifNum = 256; vif1.tag.addr = (u16)(vif1Regs->code) << 3; vif1.tag.size = vifNum * 2; } static void Vif1CMDDirectHL(){ // DIRECT/HL int vifImm; vifImm = (u16)vif1Regs->code; if (vifImm == 0) { vif1.tag.size = 65536 << 2; } else { vif1.tag.size = vifImm << 2; } } static void Vif1CMDNull(){ // invalid opcode // if ME1, then force the vif to interrupt vif1.cmd = (vif1Regs->err&0x40)?0x80:0; if ((vif1Regs->err & 0x6) == 0) { //Ignore vifcode and tag mismatch error SysPrintf( "UNKNOWN VifCmd: %x\n", vif1.cmd ); vif1Regs->stat |= 1 << 13; } } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int VIF1transfer(u32 *data, int size, int istag) { int ret; int transferred=vif1.vifstalled ? vif1.irqoffset : 0; // irqoffset necessary to add up the right qws, or else will spin (spiderman) //vif1.irqoffset = 0; #ifdef VIF_LOG VIF_LOG( "VIF1transfer: size %x (vif1.cmd %x)\n", size, vif1.cmd ); #endif //return 0; if(vif1.savedtag){ vif1.cmd = vif1.savedtag; vif1.savedtag = 0; } //vif1.irq = 0; while (size > 0) { if((vif1.cmd & 0x70) == 0x50 && istag) { vif1.savedtag = vif1.cmd; vif1.cmd = 0; continue; } if((vif1.cmd & 0x70) == 0x40 && istag && size < 2) { vif1.savedtag = vif1.cmd; vif1.cmd = 0; continue; } if (vif1.cmd & 0x7f) { //vif1Regs->stat |= VIF1_STAT_VPS_T; ret = Vif1TransTLB[(vif1.cmd & 0x7f)](data, size); data+= ret; size-= ret; transferred+= ret; //vif1Regs->stat &= ~VIF1_STAT_VPS_T; continue; } vif1Regs->stat &= ~VIF1_STAT_VPS_W; // if interrupt and new cmd is NOT MARK if(vif1.irq && ((vif1Regs->code >> 24) & 0x7f) != 0x7 && vif1.tag.size == 0) { if(vif1.tag.size > 0) SysPrintf("Stall when vif1 tagsize %x code %x\n", vif1.tag.size, vif1.cmd); break; } vif1.cmd = (data[0] >> 24); vif1Regs->code = data[0]; #ifdef VIF_LOG VIF_LOG( "VIFtransfer: cmd %x, num %x, imm %x, size %x\n", vif1.cmd, (data[0] >> 16) & 0xff, data[0] & 0xffff, size ); #endif //vif1Regs->stat |= VIF1_STAT_VPS_D; if ((vif1.cmd & 0x60) == 0x60) { vif1UNPACK(data); } else { //vif1CMD(data, size); Vif1CMDTLB[(vif1.cmd & 0x7f)](); } //vif1Regs->stat &= ~VIF1_STAT_VPS_D; if(vif1.tag.size > 0) vif1Regs->stat |= VIF1_STAT_VPS_W; ++data; --size; ++transferred; if ((vif1.cmd & 0x80) && !(vif1Regs->err & 0x1) && ((vif1Regs->code >> 24) & 0x7f) != 0x7 ) { //i bit on vifcode and not masked by VIF1_ERR #ifdef VIF_LOG VIF_LOG( "Interrupt on VIFcmd: %x (INTC_MASK = %x)\n", vif1.cmd, psHu32(INTC_MASK) ); #endif /*if((psHu32(DMAC_CTRL) & 0xC) == 0x8){ SysPrintf("VIF1 Stall on MFIFO, not implemented!\n"); }*/ vif1Regs->stat|= VIF1_STAT_VIS; ++vif1.irq; vif1.cmd &= 0x7f; } if(vif1.irq && ((vif1Regs->code >> 24) & 0x7f) != 0x7 && vif1.tag.size == 0) { break; } } // use tag.size because some game doesn't like .cmd //if( !vif1.cmd ) if( !vif1.tag.size ) vif1Regs->stat &= ~VIF1_STAT_VPS_W; if (vif1.irq > 0) { if( istag ) { return -2; } // spiderman doesn't break on qw boundaries vif1.irqoffset = transferred%4; // cannot lose the offset transferred = transferred >> 2; vif1ch->madr+= (transferred << 4); vif1ch->qwc-= transferred; //SysPrintf("Stall on vif1, FromSPR = %x, Vif1MADR = %x Sif0MADR = %x STADR = %x\n", psHu32(0x1000d010), vif1ch->madr, psHu32(0x1000c010), psHu32(DMAC_STADR)); return -2; } if( !istag ) { transferred = transferred >> 2; vif1ch->madr+= (transferred << 4); vif1ch->qwc-= transferred; } return 0; } int _VIF1chain() { u32 *pMem; u32 qwc = vif1ch->qwc; u32 ret; if (vif1ch->qwc == 0) return 0; pMem = (u32*)dmaGetAddr(vif1ch->madr); if (pMem == NULL) return -1; if( vif1.vifstalled ) { ret = VIF1transfer(pMem+vif1.irqoffset, vif1ch->qwc*4-vif1.irqoffset, 0); } else { ret = VIF1transfer(pMem, vif1ch->qwc*4, 0); } /*vif1ch->madr+= (vif1ch->qwc << 4); vif1ch->qwc-= qwc;*/ g_vifCycles+= (qwc-vif1ch->qwc)*BIAS; /* guessing */ return ret; } static int prevvifcycles = 0; static u32* prevviftag = NULL; u32 *vifptag; int _chainVIF1() { int id; //int done=0; int ret; //g_vifCycles = prevvifcycles; vifptag = (u32*)dmaGetAddr(vif1ch->tadr); //Set memory pointer to TADR if (vifptag == NULL) { //Is ptag empty? SysPrintf("Vif1 Tag BUSERR\n"); vif1ch->chcr = ( vif1ch->chcr & 0xFFFF ) | ( (*vifptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 psHu32(DMAC_STAT)|= 1<<15; //If yes, set BEIS (BUSERR) in DMAC_STAT register return -1; //Return -1 as an error has occurred } id = (vifptag[0] >> 28) & 0x7; //ID for DmaChain copied from bit 28 of the tag vif1ch->qwc = (u16)vifptag[0]; //QWC set to lower 16bits of the tag vif1ch->madr = vifptag[1]; //MADR = ADDR field g_vifCycles+=1; // Add 1 g_vifCycles from the QW read for the tag vif1ch->chcr = ( vif1ch->chcr & 0xFFFF ) | ( (*vifptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 // Transfer dma tag if tte is set vif1.done |= hwDmacSrcChainWithStack(vif1ch, id); #ifdef VIF_LOG VIF_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx\n", vifptag[1], vifptag[0], vif1ch->qwc, id, vif1ch->madr, vif1ch->tadr); #endif //} else if (!vif1.done && (psHu32(DMAC_CTRL) & 0xC0) == 0x40 && id == 4) { // STD == VIF1 // there are still bugs, need to also check if gif->madr +16*qwc >= stadr, if not, stall if( (vif1ch->madr + vif1ch->qwc * 16) >= psHu32(DMAC_STADR) ) { // stalled //SysPrintf("Vif1 Stalling %x, %x, DMA_CTRL = %x\n",vif1ch->madr, psHu32(DMAC_STADR), psHu32(DMAC_CTRL)); /*prevvifcycles = g_vifCycles; prevviftag = vifptag;*/ hwDmacIrq(13); vif1ch->tadr -= 16; FreezeMMXRegs(0); FreezeXMMRegs(0); return 2; } } prevvifcycles = 0; if (vif1ch->chcr & 0x40) { ret = VIF1transfer(vifptag+2, 2, 1); //Transfer Tag if (ret == -1) return -1; //There has been an error if (ret == -2) { vif1.vifstalled = 1; return vif1.done; //IRQ set by VIFTransfer } } #ifdef VIF_LOG VIF_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx\n", vifptag[1], vifptag[0], vif1ch->qwc, id, vif1ch->madr, vif1ch->tadr); #endif //done |= hwDmacSrcChainWithStack(vif1ch, id); ret = _VIF1chain(); //Transfers the data set by the switch if (ret == -1) { return -1; } //There's been an error if (ret == -2) { //IRQ has been set by VifTransfer vif1.vifstalled = 1; return vif1.done; } vif1.vifstalled = 0; if ((vif1ch->chcr & 0x80) && (vifptag[0] >> 31)) { //Check TIE bit of CHCR and IRQ bit of tag #ifdef VIF_LOG VIF_LOG( "dmaIrq Set\n" ); #endif //SysPrintf("VIF1 TIE\n"); //SysPrintf( "VIF1dmaIrq Set\n" ); //vif1ch->qwc = 0; //vif1Regs->stat|= VIF1_STAT_VIS; //Set the Tag Interrupt flag of VIF1_STAT vif1.done = 1; return vif1.done; //End Transfer } return vif1.done; //Return Done } static int _vif1Interrupt() { int ret; #ifdef VIF_LOG VIF_LOG("vif1Interrupt: %8.8x\n", cpuRegs.cycle); #endif if(vif1.vifstalled == 1) { if(vif1.irq) { vif1Regs->stat|= VIF1_STAT_INT; hwIntcIrq(VIF1intc); --vif1.irq; } vif1Regs->stat&= ~0x1F000000; // FQC=0 // One game doesnt like vif stalling at end, cant remember what. if(vif1.done == 1 && vif1ch->qwc == 0 && vif1.irqoffset == 0) { //SysPrintf("Vif1 Stall, done = 1 qwc = 0 irqoffset = %x, tell ref\n", vif1.irqoffset); vif1.vifstalled = 0; } else return 1; } if (vif1ch->chcr & 0x4 && vif1.done == 0 && vif1.vifstalled == 0) { if( !(psHu32(DMAC_CTRL) & 0x1) ) { SysPrintf("vif1 dma masked\n"); return 0; } g_vifCycles = 0; ret = _chainVIF1(); INT(1, g_vifCycles); return 0; } prevviftag = NULL; prevvifcycles = 0; vif1ch->chcr &= ~0x100; hwDmacIrq(DMAC_VIF1); vif1Regs->stat&= ~0x1F000000; // FQC=0 return 1; } int vif1Interrupt() { int ret; ret = _vif1Interrupt(); //FreezeXMMRegs(0); //FreezeMMXRegs(0); return ret; } void _dmaVIF1() { #ifdef VIF_LOG VIF_LOG("dmaVIF1 chcr = %lx, madr = %lx, qwc = %lx\n" " tadr = %lx, asr0 = %lx, asr1 = %lx\n", vif1ch->chcr, vif1ch->madr, vif1ch->qwc, vif1ch->tadr, vif1ch->asr0, vif1ch->asr1 ); #endif /*if ((psHu32(DMAC_CTRL) & 0xC0)) { SysPrintf("DMA Stall Control %x\n",(psHu32(DMAC_CTRL) & 0xC0)); }*/ /* Check if there is a pending irq */ /*if (vif1.irq > 0) { vif1.irq--; hwIntcIrq(VIF1intc); return; }*/ // if(vif1ch->qwc > 0) { // _VIF1chain(); // INT(1, g_vifCycles); // } vif1.done = 0; g_vifCycles = 0; /*if( prevvifcycles != 0 ) { int stallret = 0; assert( prevviftag != NULL ); vifptag = prevviftag; // transfer interrupted, so continue //_VIF1chain(); _chainVIF1(); if (vif1ch->chcr & 0x80 && vifptag[0] >> 31) { //Check TIE bit of CHCR and IRQ bit of tag #ifdef VIF_LOG VIF_LOG("dmaIrq Set\n"); #endif vif1.done = 1; INT(1, g_vifCycles); return; } //vif1.done = 1; INT(1, g_vifCycles); return; }*/ if (((psHu32(DMAC_CTRL) & 0xC) == 0x8)) { // VIF MFIFO vifMFIFOInterrupt(); return; } #ifdef PCSX2_DEVBUILD if ((psHu32(DMAC_CTRL) & 0xC0) == 0x40) { // STD == VIF1 //SysPrintf("VIF Stall Control Source = %x, Drain = %x\n", (psHu32(0xe000) >> 4) & 0x3, (psHu32(0xe000) >> 6) & 0x3); //return; } #endif vif1Regs->stat|= 0x10000000; // FQC=16 if (!(vif1ch->chcr & 0x4) || vif1ch->qwc > 0) { // Normal Mode if ((psHu32(DMAC_CTRL) & 0xC0) == 0x40) { SysPrintf("DMA Stall Control on VIF1 normal\n"); } if ((vif1ch->chcr & 0x1)) { // to Memory if(_VIF1chain() == -2) { SysPrintf("Stall on normal\n"); vif1.vifstalled = 1; return; } INT(1, g_vifCycles); } else { // from Memory if( CHECK_MULTIGS ) { u8* pTempMem, *pEndMem; u8* pMem = GSRingBufCopy(NULL, 0, GS_RINGTYPE_VIFFIFO); assert( vif1ch->qwc < 0x10000 ); *(u32*)(pMem-16) = GS_RINGTYPE_VIFFIFO|(vif1ch->qwc<<16); // hack *(u32*)(pMem-12) = vif1ch->madr; *(u32*)(pMem-8) = cpuRegs.cycle; // touch all the pages to make sure they are in memory pTempMem = dmaGetAddr(vif1ch->madr); pEndMem = (u8*)((u32)(pTempMem + vif1ch->qwc*16 + 0xfff)&~0xfff); pTempMem = (u8*)((u32)pTempMem&~0xfff); while(pTempMem < pEndMem ) { pTempMem[0] = 0; pTempMem += 0x1000; } GSRINGBUF_DONECOPY(pMem, 0); if( !CHECK_DUALCORE ) SetEvent(g_hGsEvent);//GS_SETEVENT(); // wait is, the safest option } else { int size; u64* pMem = (u64*)dmaGetAddr(vif1ch->madr); if (pMem == NULL) { //Is ptag empty? SysPrintf("Vif1 Tag BUSERR\n"); psHu32(DMAC_STAT)|= 1<<15; //If yes, set BEIS (BUSERR) in DMAC_STAT register vif1.done = 1; vif1Regs->stat&= ~0x1f000000; vif1ch->qwc = 0; INT(1, g_vifCycles); return; //Return -1 as an error has occurred } if( GSreadFIFO2 == NULL ) { for (size=vif1ch->qwc; size>0; --size) { if (size > 1) GSreadFIFO((u64*)&PS2MEM_HW[0x5000]); pMem[0] = psHu64(0x5000); pMem[1] = psHu64(0x5008); pMem+= 2; } } else { GSreadFIFO2(pMem, vif1ch->qwc); // set incase read psHu64(0x5000) = pMem[2*vif1ch->qwc-2]; psHu64(0x5008) = pMem[2*vif1ch->qwc-1]; } vif1Regs->stat&= ~0x1f000000; vif1ch->qwc = 0; INT(1, g_vifCycles); } } vif1.done = 1; return; } /* if (_VIF1chain() != 0) { INT(1, g_vifCycles); return; }*/ // Chain Mode vif1.done = 0; INT(1, g_vifCycles); } void dmaVIF1() { _dmaVIF1(); FreezeXMMRegs(0); FreezeMMXRegs(0); } void vif1Write32(u32 mem, u32 value) { if (mem == 0x10003c30) { // MARK #ifdef VIF_LOG VIF_LOG("VIF1_MARK write32 0x%8.8x\n", value); #endif /* Clear mark flag in VIF1_STAT and set mark with 'value' */ vif1Regs->stat&= ~VIF1_STAT_MRK; vif1Regs->mark = value; } else if (mem == 0x10003c10) { // FBRST #ifdef VIF_LOG VIF_LOG("VIF1_FBRST write32 0x%8.8x\n", value); #endif if (value & 0x1) { /* Reset VIF */ //SysPrintf("Vif1 Reset\n"); memset(&vif1, 0, sizeof(vif1)); vif1ch->qwc = 0; //? psHu64(0x10005000) = 0; psHu64(0x10005008) = 0; vif1.done = 1; vif1Regs->err = 0; vif1Regs->stat&= ~0x1F000000; // FQC=0 } if (value & 0x2) { /* Force Break the VIF */ /* I guess we should stop the VIF dma here but not 100% sure (linuz) */ vif1Regs->stat |= VIF1_STAT_VFS; SysPrintf("vif1 force break\n"); } if (value & 0x4) { /* Stop VIF */ /* Not completly sure about this, can't remember what game used this, but 'draining' the VIF helped it, instead of just stoppin the VIF (linuz) */ vif1Regs->stat |= VIF1_STAT_VSS; //SysPrintf("Vif1 Stop\n"); //dmaVIF1(); // Drain the VIF --- VIF Stops as not to outstrip dma source (refraction) //FreezeXMMRegs(0); } if (value & 0x8) { int cancel = 0; /* Cancel stall, first check if there is a stall to cancel, and then clear VIF1_STAT VSS|VFS|VIS|INT|ER0|ER1 bits */ if (vif1Regs->stat & (VIF1_STAT_INT|VIF1_STAT_VSS|VIF1_STAT_VIS|VIF1_STAT_VFS)) { cancel = 1; } vif1Regs->stat &= ~(VIF1_STAT_VSS | VIF1_STAT_VFS | VIF1_STAT_VIS | VIF1_STAT_INT | VIF1_STAT_ER0 | VIF1_STAT_ER1); if (cancel) { //SysPrintf("VIF1 Stall Resume\n"); if( vif1.vifstalled ) { // loop necessary for spiderman if((psHu32(DMAC_CTRL) & 0xC) == 0x8){ //vif1.vifstalled = 0; //SysPrintf("MFIFO Stall\n"); INT(10, g_vifCycles); }else { if ( _VIF1chain() != -2 ) vif1.vifstalled = 0; FreezeXMMRegs(0); FreezeMMXRegs(0); INT(1, g_vifCycles); // Gets the timing right - Flatout } } } } } else if (mem == 0x10003c20) { // ERR #ifdef VIF_LOG VIF_LOG("VIF1_ERR write32 0x%8.8x\n", value); #endif /* Set VIF1_ERR with 'value' */ vif1Regs->err = value; } else if (mem == 0x10003c00) { // STAT #ifdef VIF_LOG VIF_LOG("VIF1_STAT write32 0x%8.8x\n", value); #endif #ifdef PCSX2_DEVBUILD /* Only FDR bit is writable, so mask the rest */ if( (vif1Regs->stat & VIF1_STAT_FDR) ^ (value & VIF1_STAT_FDR) ) { // different so can't be stalled if (vif1Regs->stat & (VIF1_STAT_INT|VIF1_STAT_VSS|VIF1_STAT_VIS|VIF1_STAT_VFS)) { SysPrintf("changing dir when vif1 fifo stalled\n"); } } #endif vif1Regs->stat = (vif1Regs->stat & ~VIF1_STAT_FDR) | (value & VIF1_STAT_FDR); if (vif1Regs->stat & VIF1_STAT_FDR) { vif1Regs->stat|= 0x01000000; } else { vif1ch->qwc = 0; vif1.vifstalled = 0; vif1.done = 1; vif1Regs->stat&= ~0x1F000000; // FQC=0 } } else if (mem == 0x10003c50) { // MODE vif1Regs->mode = value; } else { SysPrintf("Unknown Vif1 write to %x\n", mem); if( mem >= 0x10003d00 && mem < 0x10003d80 ) { assert( (mem&0xf) == 0 ); if( mem < 0x10003d40) g_vifRow1[(mem>>4)&3] = value; else g_vifCol1[(mem>>4)&3] = value; } else psHu32(mem) = value; } /* Other registers are read-only so do nothing for them */ } void vif1Reset() { /* Reset the whole VIF, meaning the internal pcsx2 vars and all the registers */ memset(&vif1, 0, sizeof(vif1)); memset(vif1Regs, 0, sizeof(vif1Regs)); SetNewMask(g_vif1Masks, g_vif1HasMask3, 0, 0xffffffff); psHu64(0x10005000) = 0; psHu64(0x10005008) = 0; vif1.done = 1; vif1Regs->stat&= ~0x1F000000; // FQC=0 FreezeXMMRegs(0); FreezeMMXRegs(0); } int vif1Freeze(gzFile f, int Mode) { gzfreeze(&vif1, sizeof(vif1)); if (Mode == 0) SetNewMask(g_vif1Masks, g_vif1HasMask3, vif1Regs->mask, ~vif1Regs->mask); return 0; }