/* Pcsx2 - Pc Ps2 Emulator * Copyright (C) 2002-2003 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 */ // rewritten by zerofrog to add multithreading/gs caching to GS and VU1 #if defined(__WIN32__) #include #endif #include #include #include using namespace std; extern "C" { #define PLUGINtypedefs // for GSgifTransfer1 #include "PS2Etypes.h" #include "PS2EDefs.h" #include "zlib.h" #include "ElfHeader.h" #include "Misc.h" #include "System.h" #include "R5900.h" #include "Vif.h" #include "VU.h" #include "vifdma.h" #include "memory.h" #include "Hw.h" #include "ix86/ix86.h" #include "iR5900.h" #include "counters.h" #include "GS.h" extern _GSinit GSinit; extern _GSopen GSopen; extern _GSclose GSclose; extern _GSshutdown GSshutdown; extern _GSvsync GSvsync; extern _GSgifTransfer1 GSgifTransfer1; extern _GSgifTransfer2 GSgifTransfer2; extern _GSgifTransfer3 GSgifTransfer3; extern _GSgifSoftReset GSgifSoftReset; extern _GSreadFIFO GSreadFIFO; extern _GSreadFIFO2 GSreadFIFO2; extern _GSkeyEvent GSkeyEvent; extern _GSchangeSaveState GSchangeSaveState; extern _GSmakeSnapshot GSmakeSnapshot; extern _GSmakeSnapshot2 GSmakeSnapshot2; extern _GSirqCallback GSirqCallback; extern _GSprintf GSprintf; extern _GSsetBaseMem GSsetBaseMem; extern _GSsetGameCRC GSsetGameCRC; extern _GSsetFrameSkip GSsetFrameSkip; extern _GSreset GSreset; extern _GSwriteCSR GSwriteCSR; // could convert to pthreads easily, just don't have the time HANDLE g_hGsEvent = NULL, // set when path3 is ready to be processed g_hVuGSExit = NULL; // set when thread needs to exit HANDLE g_hGSOpen = NULL, g_hGSDone = NULL; HANDLE g_hVuGSThread = NULL; int g_FFXHack=0; #ifdef PCSX2_DEVBUILD // GS Playback int g_SaveGSStream = 0; // save GS stream; 1 - prepare, 2 - save int g_nLeftGSFrames = 0; // when saving, number of frames left gzFile g_fGSSave; // MTGS recording FILE* g_fMTGSWrite = NULL, *g_fMTGSRead = NULL; u32 g_MTGSDebug = 0, g_MTGSId = 0; #endif u32 CSRw; void gsWaitGS(); extern long pDsp; PCSX2_ALIGNED16(u8 g_MTGSMem[0x2000]); // mtgs has to have its own memory } // extern "C" #ifdef WIN32_VIRTUAL_MEM #define gif ((DMACh*)&PS2MEM_HW[0xA000]) #else #define gif ((DMACh*)&psH[0xA000]) #endif #ifdef WIN32_VIRTUAL_MEM #define PS2GS_BASE(mem) ((PS2MEM_BASE+0x12000000)+(mem&0x13ff)) #else u8 g_RealGSMem[0x2000]; #define PS2GS_BASE(mem) (g_RealGSMem+(mem&0x13ff)) #endif // dummy GS for processing SIGNAL, FINISH, and LABEL commands typedef struct { u32 nloop : 15; u32 eop : 1; u32 dummy0 : 16; u32 dummy1 : 14; u32 pre : 1; u32 prim : 11; u32 flg : 2; u32 nreg : 4; u32 regs[2]; u32 curreg; } GIFTAG; static GIFTAG g_path[3]; static PCSX2_ALIGNED16(BYTE s_byRegs[3][16]); HANDLE g_hAllGsReady[3] = {NULL}; DWORD WINAPI GSThreadProc(LPVOID lpParam); // g_pGSRingPos == g_pGSWritePos => fifo is empty u8* g_pGSRingPos = NULL, // cur pos ring is at *g_pGSWritePos = NULL; // cur pos ee thread is at extern int g_nCounters[]; extern void * memcpy_amd(void *dest, const void *src, size_t n); void gsInit() { if( CHECK_MULTIGS ) { g_hGsEvent = CreateEvent(NULL, FALSE, FALSE, NULL); g_hVuGSExit = CreateEvent(NULL, FALSE, FALSE, NULL); g_hGSOpen = CreateEvent(NULL, FALSE, FALSE, NULL); g_hGSDone = CreateEvent(NULL, FALSE, FALSE, NULL); SysPrintf("gsInit\n"); #ifdef _DEBUG assert( g_fMTGSWrite == NULL && g_fMTGSRead == NULL ); g_fMTGSWrite = fopen("mtgswrite.txt", "w"); g_fMTGSRead = fopen("mtgsread.txt", "w"); #endif g_pGSRingPos = (u8*)VirtualAlloc(GS_RINGBUFFERBASE, GS_RINGBUFFERSIZE, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); if( g_pGSRingPos != GS_RINGBUFFERBASE ) { MessageBox(NULL, "Cannot alloc GS ring buffer\n", "Error", MB_OK); exit(0); } memcpy(g_MTGSMem, PS2MEM_GS, sizeof(g_MTGSMem)); if( GSsetBaseMem != NULL ) GSsetBaseMem(g_MTGSMem); InterlockedExchangePointer(&g_pGSWritePos, GS_RINGBUFFERBASE); g_hVuGSThread = CreateThread(NULL, 0, GSThreadProc, NULL, 0, NULL); } } void gsWaitGS() { while( g_pGSRingPos != g_pGSWritePos ) Sleep(1); } void gsShutdown() { if( CHECK_MULTIGS ) { SetEvent(g_hVuGSExit); SysPrintf("Closing gs thread\n"); WaitForSingleObject(g_hVuGSThread, INFINITE); CloseHandle(g_hVuGSThread); CloseHandle(g_hGsEvent); CloseHandle(g_hVuGSExit); CloseHandle(g_hGSOpen); CloseHandle(g_hGSDone); VirtualFree(GS_RINGBUFFERBASE, GS_RINGBUFFERSIZE, MEM_DECOMMIT|MEM_RELEASE); #ifdef _DEBUG if( g_fMTGSWrite != NULL ) { fclose(g_fMTGSWrite); g_fMTGSWrite = NULL; } if( g_fMTGSRead != NULL ) { fclose(g_fMTGSRead); g_fMTGSRead = NULL; } #endif } else GSclose(); } typedef u8* PU8; u8* GSRingBufCopy(void* mem, u32 size, u32 type) { u8* writepos = g_pGSWritePos; u8* tempbuf; assert( size < GS_RINGBUFFERSIZE ); assert( writepos < GS_RINGBUFFEREND ); assert( ((u32)writepos & 15) == 0 ); assert( (size&15) == 0); size += 16; tempbuf = *(volatile PU8*)&g_pGSRingPos; if( writepos + size > GS_RINGBUFFEREND ) { // skip to beginning while( writepos < tempbuf || tempbuf == GS_RINGBUFFERBASE ) { if( !CHECK_DUALCORE ) { SetEvent(g_hGsEvent); Sleep(1); } tempbuf = *(volatile PU8*)&g_pGSRingPos; if( tempbuf == *(volatile PU8*)&g_pGSWritePos ) break; } // notify GS if( writepos != GS_RINGBUFFEREND ) { InterlockedExchangePointer(writepos, GS_RINGTYPE_RESTART); } InterlockedExchangePointer(&g_pGSWritePos, GS_RINGBUFFERBASE); writepos = GS_RINGBUFFERBASE; } while( writepos < tempbuf && (writepos+size >= tempbuf || (writepos+size == GS_RINGBUFFEREND && tempbuf == GS_RINGBUFFERBASE)) ) { if( !CHECK_DUALCORE ) { SetEvent(g_hGsEvent); Sleep(1); } tempbuf = *(volatile PU8*)&g_pGSRingPos; if( tempbuf == *(volatile PU8*)&g_pGSWritePos ) break; } // just copy *(u32*)writepos = type|(((size-16)>>4)<<16); return writepos+16; } void GSRingBufSimplePacket(int type, int data0, int data1, int data2) { u8* writepos = g_pGSWritePos; u8* tempbuf; assert( writepos + 16 <= GS_RINGBUFFEREND ); tempbuf = *(volatile PU8*)&g_pGSRingPos; if( writepos < tempbuf && writepos+16 >= tempbuf ) { do { if( !CHECK_DUALCORE ) { SetEvent(g_hGsEvent); Sleep(1); } tempbuf = *(volatile PU8*)&g_pGSRingPos; if( tempbuf == *(volatile PU8*)&g_pGSWritePos ) break; } while(writepos < tempbuf && writepos+16 >= tempbuf ); } *(u32*)writepos = type; *(int*)(writepos+4) = data0; *(int*)(writepos+8) = data1; *(int*)(writepos+12) = data2; writepos += 16; if( writepos == GS_RINGBUFFEREND ) writepos = GS_RINGBUFFERBASE; InterlockedExchangePointer(&g_pGSWritePos, writepos); if( !CHECK_DUALCORE ) SetEvent(g_hGsEvent); } void gsReset() { SysPrintf("GIF reset\n"); // GSDX crashes //if( GSreset ) GSreset(); if( CHECK_MULTIGS ) { ResetEvent(g_hGsEvent); ResetEvent(g_hVuGSExit); g_pGSRingPos = g_pGSWritePos; } memset(g_path, 0, sizeof(g_path)); memset(s_byRegs, 0, sizeof(s_byRegs)); #ifndef WIN32_VIRTUAL_MEM memset(g_RealGSMem, 0, 0x2000); #endif GSCSRr = 0x551B400F; // Set the FINISH bit to 1 for now GSIMR = 0x7f00; psHu32(GIF_STAT) = 0; psHu32(GIF_CTRL) = 0; psHu32(GIF_MODE) = 0; } void gsGIFReset() { memset(g_path, 0, sizeof(g_path)); #ifndef WIN32_VIRTUAL_MEM memset(g_RealGSMem, 0, 0x2000); #endif if( GSgifSoftReset != NULL ) GSgifSoftReset(7); if( CHECK_MULTIGS ) memset(g_path, 0, sizeof(g_path)); // else // GSreset(); GSCSRr = 0x551B400F; // Set the FINISH bit to 1 for now GSIMR = 0x7f00; psHu32(GIF_STAT) = 0; psHu32(GIF_CTRL) = 0; psHu32(GIF_MODE) = 0; } void CSRwrite(u32 value) { CSRw |= value & ~0x60; GSwriteCSR(CSRw); GSCSRr = ((GSCSRr&~value)&0x1f)|(GSCSRr&~0x1f); if( value & 0x100 ) { // FLUSH //SysPrintf("GS_CSR FLUSH GS fifo: %x (CSRr=%x)\n", value, GSCSRr); } if (value & 0x200) { // resetGS //GSCSRr = 0x400E; // The host FIFO neeeds to be empty too or GSsync will fail (saqib) //GSIMR = 0xff00; if( GSgifSoftReset != NULL ) { GSgifSoftReset(7); if( CHECK_MULTIGS ) { memset(g_path, 0, sizeof(g_path)); memset(s_byRegs, 0, sizeof(s_byRegs)); } } else GSreset(); GSCSRr = 0x551B400F; // Set the FINISH bit to 1 - GS is always at a finish state as we don't have a FIFO(saqib) //Since when!! Refraction, since 4/21/06 (zerofrog) ok ill let you off, looks like theyre all set (ref) GSIMR = 0x7F00; //This is bits 14-8 thats all that should be 1 // and this too (fixed megaman ac) //CSRw = (u32)GSCSRr; GSwriteCSR(CSRw); } } static void IMRwrite(u32 value) { GSIMR = (value & 0x1f00)|0x6000; // don't update mtgs mem } void gsWrite8(u32 mem, u8 value) { switch (mem) { case 0x12001000: // GS_CSR CSRwrite((CSRw & ~0x000000ff) | value); break; case 0x12001001: // GS_CSR CSRwrite((CSRw & ~0x0000ff00) | (value << 8)); break; case 0x12001002: // GS_CSR CSRwrite((CSRw & ~0x00ff0000) | (value << 16)); break; case 0x12001003: // GS_CSR CSRwrite((CSRw & ~0xff000000) | (value << 24)); break; default: *PS2GS_BASE(mem) = value; if( CHECK_MULTIGS ) { GSRingBufSimplePacket(GS_RINGTYPE_MEMWRITE8, mem&0x13ff, value, 0); } } #ifdef GIF_LOG GIF_LOG("GS write 8 at %8.8lx with data %8.8lx\n", mem, value); #endif } void gsConstWrite8(u32 mem, int mmreg) { switch (mem&~3) { case 0x12001000: // GS_CSR _eeMoveMMREGtoR(EAX, mmreg); iFlushCall(0); MOV32MtoR(ECX, (u32)&CSRw); AND32ItoR(EAX, 0xff<<(mem&3)*8); AND32ItoR(ECX, ~(0xff<<(mem&3)*8)); OR32ItoR(EAX, ECX); PUSH32R(EAX); CALLFunc((u32)CSRwrite); ADD32ItoR(ESP, 4); break; default: _eeWriteConstMem8( (u32)PS2GS_BASE(mem), mmreg ); if( CHECK_MULTIGS ) { _recPushReg(mmreg); iFlushCall(0); PUSH32I(mem&0x13ff); PUSH32I(GS_RINGTYPE_MEMWRITE8); CALLFunc((u32)GSRingBufSimplePacket); ADD32ItoR(ESP, 12); } break; } } extern void UpdateVSyncRate(); void gsWrite16(u32 mem, u16 value) { switch (mem) { case 0x12000010: // GS_SMODE1 if((value & 0x6000) == 0x6000) Config.PsxType |= 1; // PAL else Config.PsxType &= ~1; // NTSC *(u16*)PS2GS_BASE(mem) = value; if( CHECK_MULTIGS ) { GSRingBufSimplePacket(GS_RINGTYPE_MEMWRITE16, mem&0x13ff, value, 0); } UpdateVSyncRate(); break; case 0x12000020: // GS_SMODE2 if(value & 0x1) Config.PsxType |= 2; // Interlaced else Config.PsxType &= ~2; // Non-Interlaced *(u16*)PS2GS_BASE(mem) = value; if( CHECK_MULTIGS ) { GSRingBufSimplePacket(GS_RINGTYPE_MEMWRITE16, mem&0x13ff, value, 0); } break; case 0x12001000: // GS_CSR CSRwrite( (CSRw&0xffff0000) | value); break; case 0x12001002: // GS_CSR CSRwrite( (CSRw&0xffff) | ((u32)value<<16)); break; case 0x12001010: // GS_IMR SysPrintf("writing to IMR 16\n"); IMRwrite(value); break; default: *(u16*)PS2GS_BASE(mem) = value; if( CHECK_MULTIGS ) { GSRingBufSimplePacket(GS_RINGTYPE_MEMWRITE16, mem&0x13ff, value, 0); } } #ifdef GIF_LOG GIF_LOG("GS write 16 at %8.8lx with data %8.8lx\n", mem, value); #endif } void recSetSMODE1() { iFlushCall(0); AND32ItoR(EAX, 0x6000); CMP32ItoR(EAX, 0x6000); j8Ptr[5] = JNE8(0); // PAL OR32ItoM( (u32)&Config.PsxType, 1); j8Ptr[6] = JMP8(0); x86SetJ8( j8Ptr[5] ); // NTSC AND32ItoM( (u32)&Config.PsxType, ~1 ); x86SetJ8( j8Ptr[6] ); CALLFunc((u32)UpdateVSyncRate); } void recSetSMODE2() { TEST32ItoR(EAX, 1); j8Ptr[5] = JZ8(0); // Interlaced OR32ItoM( (u32)&Config.PsxType, 2); j8Ptr[6] = JMP8(0); x86SetJ8( j8Ptr[5] ); // Non-Interlaced AND32ItoM( (u32)&Config.PsxType, ~2 ); x86SetJ8( j8Ptr[6] ); } void gsConstWrite16(u32 mem, int mmreg) { switch (mem&~3) { case 0x12000010: // GS_SMODE1 assert( !(mem&3)); _eeMoveMMREGtoR(EAX, mmreg); _eeWriteConstMem16( (u32)PS2GS_BASE(mem), mmreg ); if( CHECK_MULTIGS ) PUSH32R(EAX); recSetSMODE1(); if( CHECK_MULTIGS ) { iFlushCall(0); PUSH32I(mem&0x13ff); PUSH32I(GS_RINGTYPE_MEMWRITE16); CALLFunc((u32)GSRingBufSimplePacket); ADD32ItoR(ESP, 12); } break; case 0x12000020: // GS_SMODE2 assert( !(mem&3)); _eeMoveMMREGtoR(EAX, mmreg); _eeWriteConstMem16( (u32)PS2GS_BASE(mem), mmreg ); if( CHECK_MULTIGS ) PUSH32R(EAX); recSetSMODE2(); if( CHECK_MULTIGS ) { iFlushCall(0); PUSH32I(mem&0x13ff); PUSH32I(GS_RINGTYPE_MEMWRITE16); CALLFunc((u32)GSRingBufSimplePacket); ADD32ItoR(ESP, 12); } break; case 0x12001000: // GS_CSR assert( !(mem&2) ); _eeMoveMMREGtoR(EAX, mmreg); iFlushCall(0); MOV32MtoR(ECX, (u32)&CSRw); AND32ItoR(EAX, 0xffff<<(mem&2)*8); AND32ItoR(ECX, ~(0xffff<<(mem&2)*8)); OR32ItoR(EAX, ECX); PUSH32R(EAX); CALLFunc((u32)CSRwrite); ADD32ItoR(ESP, 4); break; default: _eeWriteConstMem16( (u32)PS2GS_BASE(mem), mmreg ); if( CHECK_MULTIGS ) { _recPushReg(mmreg); iFlushCall(0); PUSH32I(mem&0x13ff); PUSH32I(GS_RINGTYPE_MEMWRITE16); CALLFunc((u32)GSRingBufSimplePacket); ADD32ItoR(ESP, 12); } break; } } void gsWrite32(u32 mem, u32 value) { assert( !(mem&3)); switch (mem) { case 0x12000010: // GS_SMODE1 if((value & 0x6000) == 0x6000) Config.PsxType |= 1; // PAL else Config.PsxType &= ~1; // NTSC *(u32*)PS2GS_BASE(mem) = value; UpdateVSyncRate(); if( CHECK_MULTIGS ) { GSRingBufSimplePacket(GS_RINGTYPE_MEMWRITE32, mem&0x13ff, value, 0); } break; case 0x12000020: // GS_SMODE2 if(value & 0x1) Config.PsxType |= 2; // Interlaced else Config.PsxType &= ~2; // Non-Interlaced *(u32*)PS2GS_BASE(mem) = value; if( CHECK_MULTIGS ) { GSRingBufSimplePacket(GS_RINGTYPE_MEMWRITE32, mem&0x13ff, value, 0); } break; case 0x12001000: // GS_CSR CSRwrite(value); break; case 0x12001010: // GS_IMR IMRwrite(value); break; default: *(u32*)PS2GS_BASE(mem) = value; if( CHECK_MULTIGS ) { GSRingBufSimplePacket(GS_RINGTYPE_MEMWRITE32, mem&0x13ff, value, 0); } } #ifdef GIF_LOG GIF_LOG("GS write 32 at %8.8lx with data %8.8lx\n", mem, value); #endif } // (value&0x1f00)|0x6000 void gsConstWriteIMR(int mmreg) { const u32 mem = 0x12001010; if( mmreg & MEM_XMMTAG ) { SSE2_MOVD_XMM_to_M32((u32)PS2GS_BASE(mem), mmreg&0xf); AND32ItoM((u32)PS2GS_BASE(mem), 0x1f00); OR32ItoM((u32)PS2GS_BASE(mem), 0x6000); } else if( mmreg & MEM_MMXTAG ) { SetMMXstate(); MOVDMMXtoM((u32)PS2GS_BASE(mem), mmreg&0xf); AND32ItoM((u32)PS2GS_BASE(mem), 0x1f00); OR32ItoM((u32)PS2GS_BASE(mem), 0x6000); } else if( mmreg & MEM_EECONSTTAG ) { MOV32ItoM( (u32)PS2GS_BASE(mem), (g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0]&0x1f00)|0x6000); } else { AND32ItoR(mmreg, 0x1f00); OR32ItoR(mmreg, 0x6000); MOV32RtoM( (u32)PS2GS_BASE(mem), mmreg ); } // IMR doesn't need to be updated in MTGS mode } void gsConstWrite32(u32 mem, int mmreg) { switch (mem) { case 0x12000010: // GS_SMODE1 _eeMoveMMREGtoR(EAX, mmreg); _eeWriteConstMem32( (u32)PS2GS_BASE(mem), mmreg ); if( CHECK_MULTIGS ) PUSH32R(EAX); recSetSMODE1(); if( CHECK_MULTIGS ) { iFlushCall(0); PUSH32I(mem&0x13ff); PUSH32I(GS_RINGTYPE_MEMWRITE32); CALLFunc((u32)GSRingBufSimplePacket); ADD32ItoR(ESP, 12); } break; case 0x12000020: // GS_SMODE2 _eeMoveMMREGtoR(EAX, mmreg); _eeWriteConstMem32( (u32)PS2GS_BASE(mem), mmreg ); if( CHECK_MULTIGS ) PUSH32R(EAX); recSetSMODE2(); if( CHECK_MULTIGS ) { iFlushCall(0); PUSH32I(mem&0x13ff); PUSH32I(GS_RINGTYPE_MEMWRITE32); CALLFunc((u32)GSRingBufSimplePacket); ADD32ItoR(ESP, 12); } break; case 0x12001000: // GS_CSR _recPushReg(mmreg); iFlushCall(0); CALLFunc((u32)CSRwrite); ADD32ItoR(ESP, 4); break; case 0x12001010: // GS_IMR gsConstWriteIMR(mmreg); break; default: _eeWriteConstMem32( (u32)PS2GS_BASE(mem), mmreg ); if( CHECK_MULTIGS ) { _recPushReg(mmreg); iFlushCall(0); PUSH32I(mem&0x13ff); PUSH32I(GS_RINGTYPE_MEMWRITE32); CALLFunc((u32)GSRingBufSimplePacket); ADD32ItoR(ESP, 12); } break; } } void gsWrite64(u32 mem, u64 value) { switch (mem) { case 0x12000010: // GS_SMODE1 if((value & 0x6000) == 0x6000) Config.PsxType |= 1; // PAL else Config.PsxType &= ~1; // NTSC UpdateVSyncRate(); *(u64*)PS2GS_BASE(mem) = value; if( CHECK_MULTIGS ) { GSRingBufSimplePacket(GS_RINGTYPE_MEMWRITE64, mem&0x13ff, (u32)value, (u32)(value>>32)); } break; case 0x12000020: // GS_SMODE2 if(value & 0x1) Config.PsxType |= 2; // Interlaced else Config.PsxType &= ~2; // Non-Interlaced *(u64*)PS2GS_BASE(mem) = value; if( CHECK_MULTIGS ) { GSRingBufSimplePacket(GS_RINGTYPE_MEMWRITE64, mem&0x13ff, (u32)value, 0); } break; case 0x12001000: // GS_CSR CSRwrite((u32)value); break; case 0x12001010: // GS_IMR IMRwrite((u32)value); break; default: *(u64*)PS2GS_BASE(mem) = value; if( CHECK_MULTIGS ) { GSRingBufSimplePacket(GS_RINGTYPE_MEMWRITE64, mem&0x13ff, (u32)value, (u32)(value>>32)); } } #ifdef GIF_LOG GIF_LOG("GS write 64 at %8.8lx with data %8.8lx_%8.8lx\n", mem, ((u32*)&value)[1], (u32)value); #endif } void gsConstWrite64(u32 mem, int mmreg) { switch (mem) { case 0x12000010: // GS_SMODE1 _eeMoveMMREGtoR(EAX, mmreg); _eeWriteConstMem64((u32)PS2GS_BASE(mem), mmreg); if( CHECK_MULTIGS ) PUSH32R(EAX); recSetSMODE1(); if( CHECK_MULTIGS ) { iFlushCall(0); PUSH32I(mem&0x13ff); PUSH32I(GS_RINGTYPE_MEMWRITE32); CALLFunc((u32)GSRingBufSimplePacket); ADD32ItoR(ESP, 12); } break; case 0x12000020: // GS_SMODE2 _eeMoveMMREGtoR(EAX, mmreg); _eeWriteConstMem64((u32)PS2GS_BASE(mem), mmreg); if( CHECK_MULTIGS ) PUSH32R(EAX); recSetSMODE2(); if( CHECK_MULTIGS ) { iFlushCall(0); PUSH32I(mem&0x13ff); PUSH32I(GS_RINGTYPE_MEMWRITE32); CALLFunc((u32)GSRingBufSimplePacket); ADD32ItoR(ESP, 12); } break; case 0x12001000: // GS_CSR _recPushReg(mmreg); iFlushCall(0); CALLFunc((u32)CSRwrite); ADD32ItoR(ESP, 4); break; case 0x12001010: // GS_IMR gsConstWriteIMR(mmreg); break; default: _eeWriteConstMem64((u32)PS2GS_BASE(mem), mmreg); if( CHECK_MULTIGS ) { iFlushCall(0); PUSH32M((u32)PS2GS_BASE(mem)+4); PUSH32M((u32)PS2GS_BASE(mem)); PUSH32I(mem&0x13ff); PUSH32I(GS_RINGTYPE_MEMWRITE64); CALLFunc((u32)GSRingBufSimplePacket); ADD32ItoR(ESP, 16); } break; } } void gsConstWrite128(u32 mem, int mmreg) { switch (mem) { case 0x12000010: // GS_SMODE1 _eeMoveMMREGtoR(EAX, mmreg); _eeWriteConstMem128( (u32)PS2GS_BASE(mem), mmreg); if( CHECK_MULTIGS ) PUSH32R(EAX); recSetSMODE1(); if( CHECK_MULTIGS ) { iFlushCall(0); PUSH32I(mem&0x13ff); PUSH32I(GS_RINGTYPE_MEMWRITE32); CALLFunc((u32)GSRingBufSimplePacket); ADD32ItoR(ESP, 12); } break; case 0x12000020: // GS_SMODE2 _eeMoveMMREGtoR(EAX, mmreg); _eeWriteConstMem128( (u32)PS2GS_BASE(mem), mmreg); if( CHECK_MULTIGS ) PUSH32R(EAX); recSetSMODE2(); if( CHECK_MULTIGS ) { iFlushCall(0); PUSH32I(mem&0x13ff); PUSH32I(GS_RINGTYPE_MEMWRITE32); CALLFunc((u32)GSRingBufSimplePacket); ADD32ItoR(ESP, 12); } break; case 0x12001000: // GS_CSR _recPushReg(mmreg); iFlushCall(0); CALLFunc((u32)CSRwrite); ADD32ItoR(ESP, 4); break; case 0x12001010: // GS_IMR // (value&0x1f00)|0x6000 gsConstWriteIMR(mmreg); break; default: _eeWriteConstMem128( (u32)PS2GS_BASE(mem), mmreg); if( CHECK_MULTIGS ) { iFlushCall(0); PUSH32M((u32)PS2GS_BASE(mem)+4); PUSH32M((u32)PS2GS_BASE(mem)); PUSH32I(mem&0x13ff); PUSH32I(GS_RINGTYPE_MEMWRITE64); CALLFunc((u32)GSRingBufSimplePacket); ADD32ItoR(ESP, 16); PUSH32M((u32)PS2GS_BASE(mem)+12); PUSH32M((u32)PS2GS_BASE(mem)+8); PUSH32I(mem&0x13ff); PUSH32I(GS_RINGTYPE_MEMWRITE64); CALLFunc((u32)GSRingBufSimplePacket); ADD32ItoR(ESP, 16); } break; } } u8 gsRead8(u32 mem) { #ifdef GIF_LOG GIF_LOG("GS read 8 %8.8lx, at %8.8lx\n", *(u8*)(PS2MEM_BASE+(mem&~0xc00)), mem); #endif return *(u8*)PS2GS_BASE(mem); } int gsConstRead8(u32 x86reg, u32 mem, u32 sign) { #ifdef GIF_LOG GIF_LOG("GS read 8 %8.8lx (%8.8x), at %8.8lx\n", (u32)PS2GS_BASE(mem), mem); #endif _eeReadConstMem8(x86reg, (u32)PS2GS_BASE(mem), sign); return 0; } u16 gsRead16(u32 mem) { #ifdef GIF_LOG GIF_LOG("GS read 16 %8.8lx, at %8.8lx\n", *(u16*)(PS2MEM_BASE+(mem&~0xc00)), mem); #endif return *(u16*)PS2GS_BASE(mem); } int gsConstRead16(u32 x86reg, u32 mem, u32 sign) { #ifdef GIF_LOG GIF_LOG("GS read 16 %8.8lx (%8.8x), at %8.8lx\n", (u32)PS2GS_BASE(mem), mem); #endif _eeReadConstMem16(x86reg, (u32)PS2GS_BASE(mem), sign); return 0; } u32 gsRead32(u32 mem) { #ifdef GIF_LOG GIF_LOG("GS read 32 %8.8lx, at %8.8lx\n", *(u32*)(PS2MEM_BASE+(mem&~0xc00)), mem); #endif return *(u32*)PS2GS_BASE(mem); } int gsConstRead32(u32 x86reg, u32 mem) { #ifdef GIF_LOG GIF_LOG("GS read 32 %8.8lx (%8.8x), at %8.8lx\n", (u32)PS2GS_BASE(mem), mem); #endif _eeReadConstMem32(x86reg, (u32)PS2GS_BASE(mem)); return 0; } u64 gsRead64(u32 mem) { #ifdef GIF_LOG GIF_LOG("GS read 64 %8.8lx (%8.8x), at %8.8lx\n", (u32)PS2GS_BASE(mem), mem); #endif return *(u64*)PS2GS_BASE(mem); } void gsConstRead64(u32 mem, int mmreg) { #ifdef GIF_LOG GIF_LOG("GS read 64 %8.8lx (%8.8x), at %8.8lx\n", (u32)PS2GS_BASE(mem), mem); #endif if( IS_XMMREG(mmreg) ) SSE_MOVLPS_M64_to_XMM(mmreg&0xff, (u32)PS2GS_BASE(mem)); else { MOVQMtoR(mmreg, (u32)PS2GS_BASE(mem)); SetMMXstate(); } } void gsConstRead128(u32 mem, int xmmreg) { #ifdef GIF_LOG GIF_LOG("GS read 128 %8.8lx (%8.8x), at %8.8lx\n", (u32)PS2GS_BASE(mem), mem); #endif _eeReadConstMem128( xmmreg, (u32)PS2GS_BASE(mem)); } void gsIrq() { hwIntcIrq(0); } static void GSRegHandlerSIGNAL(u32* data) { GSSIGLBLID->SIGID = (GSSIGLBLID->SIGID&~data[1])|(data[0]&data[1]); if (!(GSCSRr & 0x1)) { GSCSRr |= 1; // signal //CSRw &= ~1; } if (!(GSIMR&0x100) ) gsIrq(); } static void GSRegHandlerFINISH(u32* data) { if (!(GSCSRr & 0x2)) { //CSRw &= ~2; GSCSRr |= 2; // finish } if (!(GSIMR&0x200) ) gsIrq(); } static void GSRegHandlerLABEL(u32* data) { GSSIGLBLID->LBLID = (GSSIGLBLID->LBLID&~data[1])|(data[0]&data[1]); } typedef void (*GIFRegHandler)(u32* data); static GIFRegHandler s_GSHandlers[3] = { GSRegHandlerSIGNAL, GSRegHandlerFINISH, GSRegHandlerLABEL }; // simulates a GIF tag u32 GSgifTransferDummy(int path, u32 *pMem, u32 size) { int nreg, i, nloop; u32 curreg; u32 tempreg; GIFTAG* ptag = &g_path[path]; if( path == 0 ) { nloop = 0; } else { nloop = ptag->nloop; curreg = ptag->curreg; nreg = ptag->nreg == 0 ? 16 : ptag->nreg; } while(size > 0) { if(nloop == 0) { ptag = (GIFTAG*)pMem; nreg = ptag->nreg == 0 ? 16 : ptag->nreg; pMem+= 4; size--; if(ptag->nloop == 0 ) { if( path == 0 ) { if( ptag->eop ) return size; // ffx hack if( g_FFXHack ) continue; return size; } g_path[path].nloop = 0; // motogp graphics show if( !ptag->eop ) continue; return size; } tempreg = ptag->regs[0]; for(i = 0; i < nreg; ++i, tempreg >>= 4) { if( i == 8 ) tempreg = ptag->regs[1]; s_byRegs[path][i] = tempreg&0xf; } nloop = ptag->nloop; curreg = 0; } switch(ptag->flg) { case 0: // PACKED { for(; size > 0; size--, pMem += 4) { if( s_byRegs[path][curreg] == 0xe && (pMem[2]&0xff) >= 0x60 ) { if( (pMem[2]&0xff) < 0x64 ) s_GSHandlers[pMem[2]&0x3](pMem); } curreg++; if (nreg == curreg) { curreg = 0; if( nloop-- <= 1 ) { size--; pMem += 4; break; } } } if( nloop > 0 ) { assert(size == 0); // midnight madness cares because the tag is 5 dwords int* psrc = (int*)ptag; int* pdst = (int*)&g_path[path]; pdst[0] = psrc[0]; pdst[1] = psrc[1]; pdst[2] = psrc[2]; pdst[3] = psrc[3]; g_path[path].nloop = nloop; g_path[path].curreg = curreg; return 0; } break; } case 1: // REGLIST { size *= 2; tempreg = ptag->regs[0]; for(i = 0; i < nreg; ++i, tempreg >>= 4) { if( i == 8 ) tempreg = ptag->regs[1]; assert( (tempreg&0xf) < 0x64 ); s_byRegs[path][i] = tempreg&0xf; } for(; size > 0; pMem+= 2, size--) { if( s_byRegs[path][curreg] >= 0x60 ) s_GSHandlers[s_byRegs[path][curreg]&3](pMem); curreg++; if (nreg == curreg) { curreg = 0; if( nloop-- <= 1 ) { size--; pMem += 2; break; } } } if( size & 1 ) pMem += 2; size /= 2; if( nloop > 0 ) { assert(size == 0); // midnight madness cares because the tag is 5 dwords int* psrc = (int*)ptag; int* pdst = (int*)&g_path[path]; pdst[0] = psrc[0]; pdst[1] = psrc[1]; pdst[2] = psrc[2]; pdst[3] = psrc[3]; g_path[path].nloop = nloop; g_path[path].curreg = curreg; return 0; } break; } case 2: // GIF_IMAGE (FROM_VFRAM) case 3: { // simulate if( (int)size < nloop ) { // midnight madness cares because the tag is 5 dwords int* psrc = (int*)ptag; int* pdst = (int*)&g_path[path]; pdst[0] = psrc[0]; pdst[1] = psrc[1]; pdst[2] = psrc[2]; pdst[3] = psrc[3]; g_path[path].nloop = nloop-size; return 0; } else { pMem += nloop*4; size -= nloop; nloop = 0; } break; } } if( path == 0 && ptag->eop ) { g_path[0].nloop = 0; return size; } } g_path[path] = *ptag; g_path[path].curreg = curreg; g_path[path].nloop = nloop; return size; } int gsInterrupt() { #ifdef GIF_LOG GIF_LOG("gsInterrupt: %8.8x\n", cpuRegs.cycle); #endif if(gif->qwc > 0) { if( !(psHu32(DMAC_CTRL) & 0x1) ) { SysPrintf("gs dma masked\n"); return 0; } dmaGIF(); return 0; } gif->chcr &= ~0x100; GSCSRr &= ~0xC000; //Clear FIFO stuff GSCSRr |= 0x4000; //FIFO empty psHu32(GIF_STAT)&= ~0xE00; // OPH=0 | APATH=0 psHu32(GIF_STAT)&= ~0x1F000000; // QFC=0 hwDmacIrq(DMAC_GIF); return 1; } #define WRITERING_DMA(pMem, qwc) { \ if( CHECK_MULTIGS) { \ u8* pgsmem = GSRingBufCopy(pMem, (qwc)<<4, GS_RINGTYPE_P3); \ if( pgsmem != NULL ) { \ int sizetoread = (qwc)<<4; \ u32 pendmem = (u32)gif->madr + sizetoread; \ /* check if page of endmem is valid (dark cloud2) */ \ if( dmaGetAddr(pendmem-16) == NULL ) { \ pendmem = ((pendmem-16)&~0xfff)-16; \ while(dmaGetAddr(pendmem) == NULL) { \ pendmem = (pendmem&~0xfff)-16; \ } \ memcpy_amd(pgsmem, pMem, pendmem-(u32)gif->madr+16); \ } \ else memcpy_amd(pgsmem, pMem, sizetoread); \ \ GSRINGBUF_DONECOPY(pgsmem, sizetoread); \ GSgifTransferDummy(2, pMem, qwc); \ } \ \ if( !CHECK_DUALCORE ) SetEvent(g_hGsEvent); \ } \ else { \ FreezeMMXRegs(1); \ FreezeXMMRegs(1); \ GSGIFTRANSFER3(pMem, qwc); \ } \ } \ int _GIFchain() { u32 qwc = gif->qwc; u32 *pMem; if (qwc == 0) return 0; pMem = (u32*)dmaGetAddr(gif->madr); if (pMem == NULL) { // reset path3, fixes dark cloud 2 if( GSgifSoftReset != NULL ) GSgifSoftReset(4); if( CHECK_MULTIGS ) { memset(&g_path[2], 0, sizeof(g_path[2])); } SysPrintf("NULL GIFchain\n"); return -1; } WRITERING_DMA(pMem, qwc); gif->madr+= qwc*16; gif->qwc = 0; return (qwc)*2; } #define GIFchain() \ if (gif->qwc) { \ cycles+= _GIFchain(); /* guessing */ \ } int gscount = 0; static int prevcycles = 0; static u32* prevtag = NULL; void dmaGIF() { u32 *ptag; int done=0; int cycles=prevcycles; u32 id; /*if ((psHu32(DMAC_CTRL) & 0xC0)) { SysPrintf("DMA Stall Control %x\n",(psHu32(DMAC_CTRL) & 0xC0)); }*/ if ((psHu32(DMAC_CTRL) & 0xC) == 0xC ) { // GIF MFIFO gifMFIFOInterrupt(); return; } if( (psHu32(GIF_CTRL) & 8) ) { // temporarily stop SysPrintf("Gif dma temp paused?\n"); return; } #ifdef GIF_LOG GIF_LOG("dmaGIF chcr = %lx, madr = %lx, qwc = %lx\n" " tadr = %lx, asr0 = %lx, asr1 = %lx\n", gif->chcr, gif->madr, gif->qwc, gif->tadr, gif->asr0, gif->asr1); #endif if (psHu32(GIF_MODE) & 0x4) { } else if (vif1Regs->mskpath3 || psHu32(GIF_MODE) & 0x1) { gif->chcr &= ~0x100; psHu32(GIF_STAT)&= ~0xE00; // OPH=0 | APATH=0 hwDmacIrq(2); return; } if ((psHu32(DMAC_CTRL) & 0xC0) == 0x80 && prevcycles != 0) { // STD == GIF SysPrintf("GS Stall Control Source = %x, Drain = %x\n MADR = %x, STADR = %x", (psHu32(0xe000) >> 4) & 0x3, (psHu32(0xe000) >> 6) & 0x3,gif->madr, psHu32(DMAC_STADR)); if( gif->madr + (gif->qwc * 16) > psHu32(DMAC_STADR) ) { INT(2, cycles); return; } prevcycles = 0; gif->qwc = 0; } GSCSRr &= ~0xC000; //Clear FIFO stuff GSCSRr |= 0x8000; //FIFO full psHu32(GIF_STAT)|= 0xE00; // OPH=1 | APATH=3 psHu32(GIF_STAT)|= 0x10000000; // FQC=31, hack ;) /*if( prevcycles != 0 ) { assert( prevtag != NULL ); ptag = prevtag; id = (ptag[0] >> 28) & 0x7; //ID for DmaChain copied from bit 28 of the tag gif->qwc = (u16)ptag[0]; //QWC set to lower 16bits of the tag gif->madr = ptag[1]; //MADR = ADDR field // transfer interrupted, so continue prevcycles = 0; GIFchain(); if (gif->chcr & 0x80 && ptag[0] >> 31) { //Check TIE bit of CHCR and IRQ bit of tag #ifdef GIF_LOG GIF_LOG("dmaIrq Set\n"); #endif done = 1; } }*/ // Transfer Dn_QWC from Dn_MADR to GIF if ((gif->chcr & 0xc) == 0 || gif->qwc > 0) { // Normal Mode //gscount++; if ((psHu32(DMAC_CTRL) & 0xC0) == 0x80 && (gif->chcr & 0xc) == 0) { SysPrintf("DMA Stall Control on GIF normal\n"); } GIFchain(); } else { // Chain Mode while (done == 0) { // Loop while Dn_CHCR.STR is 1 ptag = (u32*)dmaGetAddr(gif->tadr); //Set memory pointer to TADR if (ptag == NULL) { //Is ptag empty? psHu32(DMAC_STAT)|= 1<<15; //If yes, set BEIS (BUSERR) in DMAC_STAT register break; } cycles+=2; // Add 1 cycles from the QW read for the tag // Transfer dma tag if tte is set if (gif->chcr & 0x40) { //u32 temptag[4] = {0}; #ifdef PCSX2_DEVBUILD //SysPrintf("GIF TTE: %x_%x\n", ptag[3], ptag[2]); #endif //temptag[0] = ptag[2]; //temptag[1] = ptag[3]; //GSGIFTRANSFER3(ptag, 1); } gif->chcr = ( gif->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 id = (ptag[0] >> 28) & 0x7; //ID for DmaChain copied from bit 28 of the tag gif->qwc = (u16)ptag[0]; //QWC set to lower 16bits of the tag gif->madr = ptag[1]; //MADR = ADDR field done = hwDmacSrcChainWithStack(gif, id); #ifdef GIF_LOG GIF_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx\n", ptag[1], ptag[0], gif->qwc, id, gif->madr); #endif if (!done && (psHu32(DMAC_CTRL) & 0xC0) == 0x80) { // STD == GIF // there are still bugs, need to also check if gif->madr +16*qwc >= stadr, if not, stall if( gif->madr + (gif->qwc * 16) > psHu32(DMAC_STADR) && id == 4) { // stalled SysPrintf("GS Stall Control Source = %x, Drain = %x\n MADR = %x, STADR = %x", (psHu32(0xe000) >> 4) & 0x3, (psHu32(0xe000) >> 6) & 0x3,gif->madr, psHu32(DMAC_STADR)); prevcycles = cycles; gif->tadr -= 16; hwDmacIrq(13); INT(2, cycles); FreezeMMXRegs(0); FreezeXMMRegs(0); return; } } GIFchain(); //Transfers the data set by the switch if ((gif->chcr & 0x80) && ptag[0] >> 31) { //Check TIE bit of CHCR and IRQ bit of tag #ifdef GIF_LOG GIF_LOG("dmaIrq Set\n"); #endif //SysPrintf("GIF TIE\n"); // SysPrintf("GSdmaIrq Set\n"); done = 1; //gif->qwc = 0; break; } } } prevtag = NULL; prevcycles = 0; INT(2, cycles); FreezeMMXRegs(0); FreezeXMMRegs(0); } static int mfifocycles; int mfifoGIFrbTransfer() { u32 maddr = psHu32(DMAC_RBOR); int msize = psHu32(DMAC_RBSR)+16; u32 *src; /* Check if the transfer should wrap around the ring buffer */ if ((gif->madr+gif->qwc*16) >= (maddr+msize)) { int s1 = (maddr+msize) - gif->madr; int s2 = gif->qwc*16 - s1; /* it does, so first copy 's1' bytes from 'addr' to 'data' */ src = (u32*)PSM(gif->madr); if (src == NULL) return -1; WRITERING_DMA(src, s1&~15); /* and second copy 's2' bytes from 'maddr' to '&data[s1]' */ src = (u32*)PSM(maddr); if (src == NULL) return -1; WRITERING_DMA(src, s2&~15); } else { /* it doesn't, so just transfer 'qwc*16' words from 'gif->madr' to GS */ src = (u32*)PSM(gif->madr); if (src == NULL) return -1; WRITERING_DMA(src, gif->qwc); } gif->madr+= gif->qwc*16; return 0; } int mfifoGIFchain() { u32 maddr = psHu32(DMAC_RBOR); int msize = psHu32(DMAC_RBSR)+16; u32 *pMem; /* Is QWC = 0? if so there is nothing to transfer */ if (gif->qwc == 0) return 0; if (gif->madr >= maddr && gif->madr <= (maddr+msize)) { if (mfifoGIFrbTransfer() == -1) return -1; } else { pMem = (u32*)dmaGetAddr(gif->madr); if (pMem == NULL) return -1; WRITERING_DMA(pMem, gif->qwc); gif->madr+= gif->qwc*16; } mfifocycles+= (gif->qwc) * 2; /* guessing */ gif->madr = psHu32(DMAC_RBOR) + (gif->madr & psHu32(DMAC_RBSR)); gif->qwc = 0; return 0; } #define spr0 ((DMACh*)&PS2MEM_HW[0xD000]) static int giftempqwc = 0; static int g_gifCycles = 0; static int gifqwc = 0; static int gifdone = 0; void mfifoGIFtransfer(int qwc) { u32 *ptag; int id; u32 temp = 0; mfifocycles = 0; gifqwc += qwc; g_gifCycles = 0; if(gifqwc == 0) { //#ifdef PCSX2_DEVBUILD /*if( gifqwc > 1 ) SysPrintf("gif mfifo tadr==madr but qwc = %d\n", gifqwc);*/ //#endif //INT(11,50); return; } /*if ((psHu32(DMAC_CTRL) & 0xC0)) { SysPrintf("DMA Stall Control %x\n",(psHu32(DMAC_CTRL) & 0xC0)); }*/ #ifdef GIF_LOG GIF_LOG("mfifoGIFtransfer %x madr %x, tadr %x\n", gif->chcr, gif->madr, gif->tadr); #endif if((gif->chcr & 0x100) == 0)SysPrintf("MFIFO GIF not ready!\n"); //while (qwc > 0 && done == 0) { if(gif->qwc == 0){ if(gif->tadr == spr0->madr) { #ifdef PCSX2_DEVBUILD /*if( gifqwc > 1 ) SysPrintf("gif mfifo tadr==madr but qwc = %d\n", gifqwc);*/ #endif //hwDmacIrq(14); return; } gif->tadr = psHu32(DMAC_RBOR) + (gif->tadr & psHu32(DMAC_RBSR)); ptag = (u32*)dmaGetAddr(gif->tadr); id = (ptag[0] >> 28) & 0x7; gif->qwc = (ptag[0] & 0xffff); gif->madr = ptag[1]; mfifocycles += 2; /*if(gif->chcr & 0x40) { //Not used-doesnt work :P ret = GIFtransfer(ptag+2, 2, 1); assert(ret == 0 ); // gif stall code not implemented }*/ gif->chcr = ( gif->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); #ifdef GIF_LOG GIF_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx mfifo qwc = %x spr0 madr = %x\n", ptag[1], ptag[0], gif->qwc, id, gif->madr, gif->tadr, gifqwc, spr0->madr); #endif switch (id) { case 0: // Refe - Transfer Packet According to ADDR field if(gifqwc < gif->qwc && (gif->madr & ~psHu32(DMAC_RBSR)) == psHu32(DMAC_RBOR)) { //SysPrintf("Sliced GIF MFIFO Transfer %d\n", id); return; } gif->tadr += 16; gifdone = 1; //End Transfer break; case 1: // CNT - Transfer QWC following the tag. if(gifqwc < gif->qwc && ((gif->tadr + 16) & ~psHu32(DMAC_RBSR)) == psHu32(DMAC_RBOR)) { //SysPrintf("Sliced GIF MFIFO Transfer %d\n", id); return; } gif->madr = gif->tadr + 16; //Set MADR to QW after Tag gif->tadr = gif->madr + (gif->qwc << 4); //Set TADR to QW following the data gifdone = 0; break; case 2: // Next - Transfer QWC following tag. TADR = ADDR if(gifqwc < gif->qwc && ((gif->tadr + 16) & ~psHu32(DMAC_RBSR)) == psHu32(DMAC_RBOR)) { //SysPrintf("Sliced GIF MFIFO Transfer %d\n", id); return; } temp = gif->madr; //Temporarily Store ADDR gif->madr = gif->tadr + 16; //Set MADR to QW following the tag gif->tadr = temp; //Copy temporarily stored ADDR to Tag gifdone = 0; break; case 3: // Ref - Transfer QWC from ADDR field case 4: // Refs - Transfer QWC from ADDR field (Stall Control) if(gifqwc < gif->qwc && (gif->madr & ~psHu32(DMAC_RBSR)) == psHu32(DMAC_RBOR)) { //SysPrintf("Sliced GIF MFIFO Transfer %d\n", id); return; } gif->tadr += 16; //Set TADR to next tag gifdone = 0; break; case 7: // End - Transfer QWC following the tag if(gifqwc < gif->qwc && ((gif->tadr + 16) & ~psHu32(DMAC_RBSR)) == psHu32(DMAC_RBOR)) { //SysPrintf("Sliced GIF MFIFO Transfer %d\n", id); return; } gif->madr = gif->tadr + 16; //Set MADR to data following the tag gif->tadr = gif->madr + (gif->qwc << 4); //Set TADR to QW following the data gifdone = 1; //End Transfer break; } gifqwc--; //SysPrintf("GIF MFIFO qwc %d gif qwc %d, madr = %x, tadr = %x\n", qwc, gif->qwc, gif->madr, gif->tadr); gif->tadr = psHu32(DMAC_RBOR) + (gif->tadr & psHu32(DMAC_RBSR)); if((gif->madr & ~psHu32(DMAC_RBSR)) == psHu32(DMAC_RBOR)){ gif->madr = psHu32(DMAC_RBOR) + (gif->madr & psHu32(DMAC_RBSR)); gifqwc -= gif->qwc; } } if (mfifoGIFchain() == -1) { SysPrintf("dmaChain error %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx\n", ptag[1], ptag[0], gif->qwc, id, gif->madr, gif->tadr); gifdone = 1; INT(11,mfifocycles+g_gifCycles); } if ((gif->chcr & 0x80) && (ptag[0] >> 31)) { #ifdef GIF_LOG GIF_LOG("dmaIrq Set\n"); #endif //SysPrintf("mfifoGIFtransfer: dmaIrq Set\n"); //gifqwc = 0; gifdone = 1; } // if( (cpuRegs.interrupt & (1<<1)) && qwc > 0) { // SysPrintf("gif mfifo interrupt %d\n", qwc); // } //} /*if(gifdone == 1) { gifqwc = 0; }*/ INT(11,mfifocycles+g_gifCycles); if(gifqwc == 0 && giftempqwc > 0) hwDmacIrq(14); //hwDmacIrq(1); #ifdef SPR_LOG SPR_LOG("mfifoGIFtransfer end %x madr %x, tadr %x\n", gif->chcr, gif->madr, gif->tadr); #endif } int gifMFIFOInterrupt() { mfifocycles = 0; if(!(gif->chcr & 0x100)) return 1; else if(gifqwc == 0 && gifdone == 0) return 1; if(gifdone == 0 && gifqwc != 0) { mfifoGIFtransfer(0); if(gif->qwc > 0) return 1; else return 0; } if(gifdone == 0 || gif->qwc > 0) { SysPrintf("Shouldnt go here\n"); return 1; } gifdone = 0; gif->chcr &= ~0x100; hwDmacIrq(DMAC_GIF); return 1; } DWORD WINAPI GSThreadProc(LPVOID lpParam) { HANDLE handles[2] = { g_hGsEvent, g_hVuGSExit }; //SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); u8* writepos; u32 tag; u32 counter = 0; { int ret; HANDLE openhandles[2] = { g_hGSOpen, g_hVuGSExit }; if( WaitForMultipleObjects(2, openhandles, FALSE, INFINITE) == WAIT_OBJECT_0+1 ) { return 0; } ret = GSopen((void *)&pDsp, "PCSX2", 1); GSCSRr = 0x551B400F; // 0x55190000 SysPrintf("gsOpen done\n"); if (ret != 0) { SysMessage ("Error Opening GS Plugin"); return (DWORD)-1; } SetEvent(g_hGSDone); } SysPrintf("Starting GS thread\n"); while(1) { if( !CHECK_DUALCORE ) { if( WaitForMultipleObjects(2, handles, FALSE, INFINITE) == WAIT_OBJECT_0+1 ) { GSclose(); return 0; } } else if( !(counter++ & 0xffff) ) { if( WaitForSingleObject(g_hVuGSExit, 0) == WAIT_OBJECT_0 ) { GSclose(); return 0; } } if( g_pGSRingPos != g_pGSWritePos ) { do { writepos = *(volatile PU8*)&g_pGSWritePos; while( g_pGSRingPos != writepos ) { assert( g_pGSRingPos < GS_RINGBUFFEREND ); // process until writepos tag = *(u32*)g_pGSRingPos; switch( tag&0xffff ) { case GS_RINGTYPE_RESTART: InterlockedExchangePointer(&g_pGSRingPos, GS_RINGBUFFERBASE); if( GS_RINGBUFFERBASE == writepos ) goto ExitGS; continue; case GS_RINGTYPE_P1: MTGS_RECREAD(g_pGSRingPos+16, ((tag>>16)<<4)); GSgifTransfer1((u32*)(g_pGSRingPos+16), 0); InterlockedExchangeAdd((PLONG)&g_pGSRingPos, 16 + ((tag>>16)<<4)); break; case GS_RINGTYPE_P2: MTGS_RECREAD(g_pGSRingPos+16, ((tag>>16)<<4)); GSgifTransfer2((u32*)(g_pGSRingPos+16), tag>>16); InterlockedExchangeAdd((PLONG)&g_pGSRingPos, 16 + ((tag>>16)<<4)); break; case GS_RINGTYPE_P3: MTGS_RECREAD(g_pGSRingPos+16, ((tag>>16)<<4)); GSgifTransfer3((u32*)(g_pGSRingPos+16), tag>>16); InterlockedExchangeAdd((PLONG)&g_pGSRingPos, 16 + ((tag>>16)<<4)); break; case GS_RINGTYPE_VSYNC: GSvsync(*(int*)(g_pGSRingPos+4)); InterlockedExchangeAdd((PLONG)&g_pGSRingPos, 16); break; case GS_RINGTYPE_FRAMESKIP: GSsetFrameSkip(*(int*)(g_pGSRingPos+4)); InterlockedExchangeAdd((PLONG)&g_pGSRingPos, 16); break; case GS_RINGTYPE_MEMWRITE8: g_MTGSMem[*(int*)(g_pGSRingPos+4)] = *(u8*)(g_pGSRingPos+8); InterlockedExchangeAdd((PLONG)&g_pGSRingPos, 16); break; case GS_RINGTYPE_MEMWRITE16: *(u16*)(g_MTGSMem+*(int*)(g_pGSRingPos+4)) = *(u16*)(g_pGSRingPos+8); InterlockedExchangeAdd((PLONG)&g_pGSRingPos, 16); break; case GS_RINGTYPE_MEMWRITE32: *(u32*)(g_MTGSMem+*(int*)(g_pGSRingPos+4)) = *(u32*)(g_pGSRingPos+8); InterlockedExchangeAdd((PLONG)&g_pGSRingPos, 16); break; case GS_RINGTYPE_MEMWRITE64: *(u64*)(g_MTGSMem+*(int*)(g_pGSRingPos+4)) = *(u64*)(g_pGSRingPos+8); InterlockedExchangeAdd((PLONG)&g_pGSRingPos, 16); break; case GS_RINGTYPE_VIFFIFO: { u64* pMem; assert( vif1ch->madr == *(u32*)(g_pGSRingPos+4) ); assert( vif1ch->qwc == (tag>>16) ); assert( vif1ch->madr == *(u32*)(g_pGSRingPos+4) ); pMem = (u64*)dmaGetAddr(vif1ch->madr); if (pMem == NULL) { psHu32(DMAC_STAT)|= 1<<15; break; } if( GSreadFIFO2 == NULL ) { int size; for (size=(tag>>16); size>0; size--) { GSreadFIFO((u64*)&PS2MEM_HW[0x5000]); pMem[0] = psHu64(0x5000); pMem[1] = psHu64(0x5008); pMem+= 2; } } else { GSreadFIFO2(pMem, tag>>16); // set incase read psHu64(0x5000) = pMem[2*(tag>>16)-2]; psHu64(0x5008) = pMem[2*(tag>>16)-1]; } assert( vif1ch->madr == *(u32*)(g_pGSRingPos+4) ); assert( vif1ch->qwc == (tag>>16) ); tag = (tag>>16) - (cpuRegs.cycle- *(u32*)(g_pGSRingPos+8)); if( tag & 0x80000000 ) tag = 0; vif1Regs->stat&= ~0x1f000000; vif1ch->qwc = 0; INT(1, tag); InterlockedExchangeAdd((PLONG)&g_pGSRingPos, 16); break; } default: SysPrintf("GSThreadProc, bad packet writepos: %x g_pGSRingPos: %x, g_pGSWritePos: %x\n", writepos, g_pGSRingPos, g_pGSWritePos); assert(0); g_pGSRingPos = g_pGSWritePos; //flushall(); } assert( g_pGSRingPos <= GS_RINGBUFFEREND ); if( g_pGSRingPos == GS_RINGBUFFEREND ) InterlockedExchangePointer(&g_pGSRingPos, GS_RINGBUFFERBASE); if( g_pGSRingPos == g_pGSWritePos ) { break; } } ExitGS: ; } while(g_pGSRingPos != *(volatile PU8*)&g_pGSWritePos); } // process vu1 } return 0; } int gsFreeze(gzFile f, int Mode) { gzfreeze(PS2MEM_GS, 0x2000); gzfreeze(&CSRw, sizeof(CSRw)); gzfreeze(g_path, sizeof(g_path)); gzfreeze(s_byRegs, sizeof(s_byRegs)); return 0; } #ifdef PCSX2_DEVBUILD struct GSStatePacket { u32 type; vector mem; }; // runs the GS void RunGSState(gzFile f) { u32 newfield; list< GSStatePacket > packets; while(!gzeof(f)) { int type, size; gzread(f, &type, sizeof(type)); if( type != GSRUN_VSYNC ) gzread(f, &size, 4); packets.push_back(GSStatePacket()); GSStatePacket& p = packets.back(); p.type = type; if( type != GSRUN_VSYNC ) { p.mem.resize(size*16); gzread(f, &p.mem[0], size*16); } } list::iterator it = packets.begin(); g_SaveGSStream = 3; int skipfirst = 0; // first extract the data while(1) { switch(it->type) { case GSRUN_TRANS1: GSgifTransfer1((u32*)&it->mem[0], 0); break; case GSRUN_TRANS2: GSgifTransfer2((u32*)&it->mem[0], it->mem.size()/16); break; case GSRUN_TRANS3: GSgifTransfer3((u32*)&it->mem[0], it->mem.size()/16); break; case GSRUN_VSYNC: // flip newfield = (*(u32*)(PS2MEM_GS+0x1000)&0x2000) ? 0 : 0x2000; *(u32*)(PS2MEM_GS+0x1000) = (*(u32*)(PS2MEM_GS+0x1000) & ~(1<<13)) | newfield; GSvsync(newfield); SysUpdate(); // if( g_SaveGSStream != 3 ) // return; // // if( skipfirst ) { // ++it; // it = packets.erase(packets.begin(), it); // skipfirst = 0; // } // it = packets.begin(); continue; break; default: assert(0); } ++it; if( it == packets.end() ) it = packets.begin(); } } #endif #undef GIFchain