mirror of
https://github.com/PCSX2/pcsx2.git
synced 2025-04-02 10:52:54 -04:00
git-svn-id: http://pcsx2.googlecode.com/svn/branches/pcsx2_0.9.1@159 96395faa-99c1-11dd-bbfe-3dabce05a288
1707 lines
No EOL
40 KiB
C
1707 lines
No EOL
40 KiB
C
/* 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
|
|
|
|
#include "Common.h"
|
|
|
|
#include <xmmintrin.h>
|
|
|
|
#include <assert.h>
|
|
#include "ir5900.h"
|
|
#include "VUmicro.h"
|
|
|
|
#ifdef WIN32_VIRTUAL_MEM
|
|
#define gif ((DMACh*)&PS2MEM_HW[0xA000])
|
|
#else
|
|
#define gif ((DMACh*)&psH[0xA000])
|
|
#endif
|
|
|
|
#define ENABLE_GS_CACHING_SIZE 0x4000 // min size
|
|
//#define _RINGBUF_DEBUG
|
|
|
|
#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
|
|
|
|
#ifdef GSCAPTURE
|
|
u32 g_loggs = 0;
|
|
u32 g_gstransnum = 0;
|
|
u32 g_gslimit = 0;
|
|
u32 g_gsfinalnum = 0;
|
|
#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];
|
|
__declspec(align(16)) static BYTE s_byRegs[3][16];
|
|
|
|
// 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;
|
|
u32 CSRw;
|
|
|
|
HANDLE g_hAllGsReady[3] = {NULL};
|
|
|
|
DWORD WINAPI VuGSThreadProc(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
|
|
u8 *g_pGSTempWritePos = NULL, *g_pGSTempReadPos = NULL; // cur pos ee thread is at
|
|
|
|
extern int g_nCounters[];
|
|
|
|
extern void * memcpy_amd(void *dest, const void *src, size_t n);
|
|
|
|
CRITICAL_SECTION g_PageAddrSection;
|
|
u32 *g_pGSCurFreePages = NULL, *g_pGSWriteFreePages = NULL;
|
|
|
|
void gsInit()
|
|
{
|
|
if( VirtualAlloc(GS_PAGEADDRS, GSPAGES_STRIDE*(0x10000000>>GS_SHIFT), MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE) != GS_PAGEADDRS ) {
|
|
MessageBox(NULL, "Cannot alloc GS page buffer\n", "Error", MB_OK);
|
|
exit(0);
|
|
}
|
|
memset(GS_PAGEADDRS, 0, GSPAGES_STRIDE*(0x02000000>>GS_SHIFT));
|
|
|
|
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");
|
|
|
|
g_pGSRingPos = 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);
|
|
}
|
|
|
|
g_pGSTempReadPos = g_pGSTempWritePos = VirtualAlloc(GS_RINGTEMPBASE, GS_RINGTEMPSIZE, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
|
|
if( g_pGSTempWritePos != GS_RINGTEMPBASE ) {
|
|
MessageBox(NULL, "Cannot alloc GS RingTemp buffer\n", "Error", MB_OK);
|
|
exit(0);
|
|
}
|
|
|
|
InitializeCriticalSection(&g_PageAddrSection);
|
|
|
|
InterlockedExchangePointer(&g_pGSWritePos, GS_RINGBUFFERBASE);
|
|
g_hVuGSThread = CreateThread(NULL, 0, VuGSThreadProc, NULL, 0, NULL);
|
|
}
|
|
}
|
|
|
|
void gsWaitGS()
|
|
{
|
|
while( g_pGSRingPos != g_pGSWritePos )
|
|
Sleep(1);
|
|
}
|
|
|
|
void gsShutdown()
|
|
{
|
|
VirtualFree(GS_PAGEADDRS, GSPAGES_STRIDE*(0x02000000>>GS_SHIFT), MEM_DECOMMIT|MEM_RELEASE);
|
|
|
|
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);
|
|
|
|
g_pGSWriteFreePages = g_pGSCurFreePages = NULL;
|
|
g_pGSTempReadPos = NULL;
|
|
|
|
DeleteCriticalSection(&g_PageAddrSection);
|
|
|
|
VirtualFree(GS_RINGBUFFERBASE, GS_RINGBUFFERSIZE, MEM_DECOMMIT|MEM_RELEASE);
|
|
VirtualFree(GS_RINGTEMPBASE, GS_RINGTEMPSIZE, MEM_DECOMMIT|MEM_RELEASE);
|
|
}
|
|
else GSclose();
|
|
}
|
|
|
|
static void GSRingTempReserve(u32 size)
|
|
{
|
|
u8* writepos = g_pGSTempWritePos;
|
|
assert( size <= GS_RINGTEMPSIZE );
|
|
|
|
// there always has to be memory
|
|
if( g_pGSTempWritePos + size > GS_RINGTEMPEND ) {
|
|
if( writepos < g_pGSTempReadPos ) {
|
|
do {
|
|
SetEvent(g_hGsEvent);
|
|
Sleep(1);
|
|
} while( writepos < g_pGSTempReadPos );
|
|
}
|
|
|
|
// notify GS
|
|
writepos = GS_RINGTEMPBASE;
|
|
}
|
|
|
|
if( writepos < g_pGSTempReadPos && writepos+size >= g_pGSTempReadPos ) {
|
|
do {
|
|
SetEvent(g_hGsEvent);
|
|
Sleep(1);
|
|
} while( writepos < g_pGSTempReadPos && writepos+size >= g_pGSTempReadPos );
|
|
}
|
|
|
|
g_pGSTempWritePos = writepos;
|
|
}
|
|
|
|
static u8* GSRingTempCopy(u32 size)
|
|
{
|
|
u8* writepos;
|
|
assert( size <= GS_RINGTEMPSIZE );
|
|
//GSRingTempReserve(size);
|
|
|
|
writepos = g_pGSTempWritePos;
|
|
g_pGSTempWritePos += size;
|
|
assert( g_pGSTempWritePos <= GS_RINGTEMPEND );
|
|
|
|
//SysPrintf("writepos copy: %x %d\n", writepos, size);
|
|
return writepos;
|
|
}
|
|
|
|
typedef u8* PU8;
|
|
|
|
u8* GSRingBufCopy(void* mem, u32 size, u32 type)
|
|
{
|
|
u8* writepos = g_pGSWritePos;
|
|
u8* tempbuf;
|
|
assert( size < 0x10000*16 );
|
|
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 ) {
|
|
SetEvent(g_hGsEvent);
|
|
Sleep(1);
|
|
tempbuf = *(volatile PU8*)&g_pGSRingPos;
|
|
}
|
|
|
|
// notify GS
|
|
if( writepos != GS_RINGBUFFEREND ) {
|
|
*(u32*)writepos = GS_RINGTYPE_RESTART;
|
|
}
|
|
|
|
writepos = GS_RINGBUFFERBASE;
|
|
}
|
|
|
|
while( writepos < tempbuf && (writepos+size >= g_pGSRingPos || (writepos+size == GS_RINGBUFFEREND && g_pGSRingPos == GS_RINGBUFFERBASE)) ) {
|
|
SetEvent(g_hGsEvent);
|
|
Sleep(1);
|
|
tempbuf = *(volatile PU8*)&g_pGSRingPos;
|
|
}
|
|
|
|
#ifdef WIN32_VIRTUAL_MEM
|
|
if( ENABLE_GS_CACHING && size >= ENABLE_GS_CACHING_SIZE && mem != NULL && (u8*)mem < PS2MEM_BASE+0x10000000 ) {
|
|
u32 val;
|
|
u32 i;
|
|
u32* page = GS_PAGEADDRS+(((u32)((u8*)mem-PS2MEM_BASE)&0x01ffffff)>>GS_SHIFT)*(GSPAGES_MEMADDRS+1);
|
|
u32 numpages = (((u32)mem+size-1)>>GS_SHIFT) - ((u32)mem>>GS_SHIFT)+1;
|
|
|
|
// inc all pages
|
|
for(i = 0; i < numpages; ++i) {
|
|
if( (u8)page[0] >= GSPAGES_MEMADDRS )
|
|
break;
|
|
|
|
val = InterlockedExchangeAdd(page, 0x40000001);
|
|
|
|
assert( (u8)val < GSPAGES_MEMADDRS );
|
|
|
|
// upper 2 bits are index
|
|
page[(val>>30)+1] = (u32)writepos;
|
|
page += GSPAGES_MEMADDRS+1;
|
|
}
|
|
|
|
if( i == numpages ) {
|
|
// succeeded, so fill necessary data
|
|
*(u32*)writepos = GS_RINGTYPE_MEMREF|type|(((size-16)>>4)<<16);
|
|
*(u32*)(writepos+4) = (u32)mem;
|
|
*(u32*)(writepos+8) = (u32)(page-(GSPAGES_MEMADDRS+1)*numpages);
|
|
*(u32*)(writepos+12) = (u32)numpages;
|
|
|
|
writepos += 16;
|
|
|
|
#ifndef _RINGBUF_DEBUG
|
|
if( writepos == GS_RINGBUFFEREND ) writepos = GS_RINGBUFFERBASE;
|
|
InterlockedExchangePointer(&g_pGSWritePos, writepos);
|
|
|
|
// SetEvent(g_hGsEvent);
|
|
// while( g_pGSWritePos != g_pGSRingPos ) Sleep(1);
|
|
|
|
return NULL;
|
|
#else
|
|
return writepos;
|
|
#endif
|
|
}
|
|
|
|
SysPrintf("not enough pages %x, %d\n", mem, size);
|
|
|
|
// BUG, the interlocked exchange add should be done in a crit section!
|
|
// dec the current pages
|
|
while(i-- > 0) {
|
|
page -= GSPAGES_MEMADDRS+1;
|
|
InterlockedExchangeAdd(page, -0x40000001);
|
|
}
|
|
|
|
// don't have enough mem, so fall through
|
|
}
|
|
#endif
|
|
|
|
// just copy
|
|
*(u32*)writepos = type|(((size-16)>>4)<<16);
|
|
return writepos+16;
|
|
}
|
|
|
|
void GSRingBufVSync(int field)
|
|
{
|
|
u8* writepos = g_pGSWritePos;
|
|
u8* tempbuf;
|
|
|
|
assert( writepos + 16 <= GS_RINGBUFFEREND );
|
|
|
|
tempbuf = *(volatile PU8*)&g_pGSRingPos;
|
|
if( writepos < tempbuf && writepos+16 >= tempbuf ) {
|
|
|
|
do {
|
|
SetEvent(g_hGsEvent);
|
|
Sleep(1);
|
|
tempbuf = *(volatile PU8*)&g_pGSRingPos;
|
|
} while(writepos < tempbuf && writepos+16 >= tempbuf );
|
|
}
|
|
|
|
*(u32*)writepos = GS_RINGTYPE_VSYNC;
|
|
*(int*)(writepos+4) = field;
|
|
|
|
writepos += 16;
|
|
if( writepos == GS_RINGBUFFEREND ) writepos = GS_RINGBUFFERBASE;
|
|
InterlockedExchangePointer(&g_pGSWritePos, writepos);
|
|
|
|
if( !CHECK_DUALCORE )
|
|
SetEvent(g_hGsEvent);
|
|
}
|
|
|
|
// called from gs thread or exception handler
|
|
static void GSFreeRingBuf(u8* pringbuf)
|
|
{
|
|
u32 mem = *(u32*)(pringbuf+4) & ~0xfff;
|
|
u32* pageaddr = *(u32**)(pringbuf+8);
|
|
u32 pages = *(u32*)(pringbuf+12);
|
|
u32 val, index;
|
|
|
|
mem &= ~0xfff;
|
|
|
|
while(pages-- > 0 ) {
|
|
|
|
val = pageaddr[0];
|
|
assert( (val&0xff) > 0 );
|
|
|
|
index = (((val>>30)-(val&7))&3);
|
|
|
|
if( pageaddr[ index + 1 ] != (u32)pringbuf ) {
|
|
// deleting before others, so remove it from the entry
|
|
for(val = 1; val < 5; ++val ) {
|
|
if( pageaddr[val] == (u32)pringbuf ) {
|
|
|
|
val--;
|
|
|
|
// shift the rest
|
|
while(index != val) {
|
|
pageaddr[1+(val)%GSPAGES_MEMADDRS] = pageaddr[(val-1)%GSPAGES_MEMADDRS+1];
|
|
val = (val-1)%GSPAGES_MEMADDRS;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
InterlockedExchangeAdd(pageaddr, -1);
|
|
mem += 0x1000;
|
|
pageaddr += GSPAGES_MEMADDRS+1;
|
|
}
|
|
}
|
|
|
|
void GSFreePage(u32* page)
|
|
{
|
|
u32 indices, num;
|
|
u32 gssize;
|
|
u8* gsmem, *ringmem;
|
|
|
|
num = *(u32*)page;
|
|
|
|
// count approximately the size needed to be allocated
|
|
indices = ((num>>30)-(num&0xff))&3;
|
|
num &= 0xff;
|
|
gssize = 0;
|
|
|
|
while(num-- > 0) {
|
|
// first copy to a new memory
|
|
ringmem = *(u8**)(page + 1 + indices);
|
|
gssize += (*(u32*)ringmem >> 16) << 4;
|
|
// go to the next index
|
|
indices = (indices+1)%GSPAGES_MEMADDRS;
|
|
}
|
|
|
|
GSRingTempReserve(gssize);
|
|
|
|
// lock section to start freeing
|
|
EnterCriticalSection(&g_PageAddrSection);
|
|
|
|
// check again since could have changed
|
|
num = *(u32*)page;
|
|
if( (u8)num ) {
|
|
// note that values might be different
|
|
indices = ((num>>30)-(num&0xff))&3;
|
|
num &= 0xff;
|
|
|
|
while(num-- > 0) {
|
|
// first copy to a new memory
|
|
ringmem = *(u8**)(page + 1 + indices);
|
|
|
|
assert( !(*(u32*)ringmem & GS_RINGTYPE_MEMNOFREE) );
|
|
|
|
gssize = (*(u32*)ringmem >> 16) << 4;
|
|
gsmem = GSRingTempCopy(gssize);
|
|
memcpy(gsmem, *(u8**)(ringmem+4), gssize);
|
|
|
|
GSFreeRingBuf(ringmem);
|
|
|
|
// indicate that using different mem
|
|
*(u8**)(ringmem+4) = gsmem;
|
|
*(u32*)ringmem |= GS_RINGTYPE_MEMNOFREE;
|
|
|
|
// go to the next index
|
|
indices = (indices+1)%GSPAGES_MEMADDRS;
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(&g_PageAddrSection);
|
|
}
|
|
|
|
void gsReset()
|
|
{
|
|
SysPrintf("GIF reset\n");
|
|
|
|
// GSDX crashes
|
|
//if( GSreset ) GSreset();
|
|
memset(GS_PAGEADDRS, 0, GSPAGES_STRIDE*(0x02000000>>GS_SHIFT));
|
|
|
|
if( CHECK_MULTIGS ) {
|
|
ResetEvent(g_hGsEvent);
|
|
ResetEvent(g_hVuGSExit);
|
|
|
|
g_pGSRingPos = g_pGSWritePos;
|
|
g_pGSCurFreePages = g_pGSWriteFreePages;
|
|
g_pGSTempReadPos = g_pGSTempWritePos = GS_RINGTEMPBASE;
|
|
}
|
|
|
|
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 = 0x551B4000; // 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);
|
|
// else
|
|
// GSreset();
|
|
|
|
GSCSRr = 0x551B4000; // 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)
|
|
{
|
|
GSwriteCSR(value);
|
|
|
|
GSCSRr = ((GSCSRr&~value)&0x1f)|(GSCSRr&~0x1f);
|
|
|
|
if( value & 0x100 ) { // FLUSH
|
|
//SysPrintf("GS_CSR FLUSH GS fifo: %x (CSRr=%x)\n", value, GSCSRr);
|
|
}
|
|
|
|
CSRw |= value & ~0x60;
|
|
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);
|
|
else GSreset();
|
|
|
|
GSCSRr = 0x551B4002; // 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)
|
|
GSIMR = 0x7F00; //This is bits 14-8 thats all that should be 1
|
|
|
|
// and this too (fixed megaman ac)
|
|
GSwriteCSR(GSCSRr);
|
|
}
|
|
}
|
|
|
|
static void IMRwrite(u32 value) {
|
|
GSIMR = (value & 0x1f00)|0x6000;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
#ifdef HW_LOG
|
|
HW_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 );
|
|
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;
|
|
UpdateVSyncRate();
|
|
break;
|
|
|
|
case 0x12000020: // GS_SMODE2
|
|
if(value & 0x1) Config.PsxType |= 2; // Interlaced
|
|
else Config.PsxType &= ~2; // Non-Interlaced
|
|
*(u16*)PS2GS_BASE(mem) = value;
|
|
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;
|
|
}
|
|
|
|
#ifdef HW_LOG
|
|
HW_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 );
|
|
recSetSMODE1();
|
|
break;
|
|
|
|
case 0x12000020: // GS_SMODE2
|
|
assert( !(mem&3));
|
|
_eeMoveMMREGtoR(EAX, mmreg);
|
|
_eeWriteConstMem16( (u32)PS2GS_BASE(mem), mmreg );
|
|
recSetSMODE2();
|
|
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 );
|
|
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();
|
|
break;
|
|
case 0x12000020: // GS_SMODE2
|
|
if(value & 0x1) Config.PsxType |= 2; // Interlaced
|
|
else Config.PsxType &= ~2; // Non-Interlaced
|
|
*(u32*)PS2GS_BASE(mem) = value;
|
|
break;
|
|
|
|
case 0x12001000: // GS_CSR
|
|
CSRwrite(value);
|
|
break;
|
|
|
|
case 0x12001010: // GS_IMR
|
|
IMRwrite(value);
|
|
break;
|
|
default:
|
|
*(u32*)PS2GS_BASE(mem) = value;
|
|
}
|
|
|
|
#ifdef HW_LOG
|
|
HW_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 );
|
|
}
|
|
}
|
|
void gsConstWrite32(u32 mem, int mmreg) {
|
|
|
|
switch (mem) {
|
|
|
|
case 0x12000010: // GS_SMODE1
|
|
_eeMoveMMREGtoR(EAX, mmreg);
|
|
_eeWriteConstMem32( (u32)PS2GS_BASE(mem), mmreg );
|
|
recSetSMODE1();
|
|
break;
|
|
|
|
case 0x12000020: // GS_SMODE2
|
|
_eeMoveMMREGtoR(EAX, mmreg);
|
|
_eeWriteConstMem32( (u32)PS2GS_BASE(mem), mmreg );
|
|
recSetSMODE2();
|
|
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 );
|
|
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;
|
|
break;
|
|
|
|
case 0x12000020: // GS_SMODE2
|
|
if(value & 0x1) Config.PsxType |= 2; // Interlaced
|
|
else Config.PsxType &= ~2; // Non-Interlaced
|
|
*(u64*)PS2GS_BASE(mem) = value;
|
|
break;
|
|
case 0x12001000: // GS_CSR
|
|
CSRwrite((u32)value);
|
|
break;
|
|
|
|
case 0x12001010: // GS_IMR
|
|
IMRwrite((u32)value);
|
|
break;
|
|
|
|
default:
|
|
*(u64*)PS2GS_BASE(mem) = value;
|
|
}
|
|
|
|
#ifdef HW_LOG
|
|
HW_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);
|
|
recSetSMODE1();
|
|
break;
|
|
|
|
case 0x12000020: // GS_SMODE2
|
|
_eeMoveMMREGtoR(EAX, mmreg);
|
|
_eeWriteConstMem64((u32)PS2GS_BASE(mem), mmreg);
|
|
recSetSMODE2();
|
|
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);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void gsConstWrite128(u32 mem, int mmreg)
|
|
{
|
|
switch (mem) {
|
|
case 0x12000010: // GS_SMODE1
|
|
_eeMoveMMREGtoR(EAX, mmreg);
|
|
_eeWriteConstMem128( (u32)PS2GS_BASE(mem), mmreg);
|
|
recSetSMODE1();
|
|
break;
|
|
|
|
case 0x12000020: // GS_SMODE2
|
|
_eeMoveMMREGtoR(EAX, mmreg);
|
|
_eeWriteConstMem128( (u32)PS2GS_BASE(mem), mmreg);
|
|
recSetSMODE2();
|
|
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);
|
|
break;
|
|
}
|
|
}
|
|
|
|
u8 gsRead8(u32 mem)
|
|
{
|
|
#ifdef HW_LOG
|
|
//HW_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)
|
|
{
|
|
_eeReadConstMem8(x86reg, (u32)PS2GS_BASE(mem), sign);
|
|
return 0;
|
|
}
|
|
|
|
u16 gsRead16(u32 mem)
|
|
{
|
|
#ifdef HW_LOG
|
|
//HW_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)
|
|
{
|
|
_eeReadConstMem16(x86reg, (u32)PS2GS_BASE(mem), sign);
|
|
return 0;
|
|
}
|
|
|
|
u32 gsRead32(u32 mem) {
|
|
|
|
#ifdef HW_LOG
|
|
//HW_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)
|
|
{
|
|
_eeReadConstMem32(x86reg, (u32)PS2GS_BASE(mem));
|
|
return 0;
|
|
}
|
|
|
|
u64 gsRead64(u32 mem)
|
|
{
|
|
#ifdef HW_LOG
|
|
//HW_LOG("GS read 64 %8.8lx (%8.8x), at %8.8lx\n", *(u64*)(PS2MEM_BASE+(mem&~0xc00)), mem);
|
|
#endif
|
|
|
|
return *(u64*)PS2GS_BASE(mem);
|
|
}
|
|
|
|
void gsConstRead64(u32 mem, int mmreg)
|
|
{
|
|
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)
|
|
{
|
|
_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 (CSRw & 0x1) {
|
|
GSCSRr |= 1; // signal
|
|
//CSRw &= ~1;
|
|
}
|
|
if (!(GSIMR&0x100) )
|
|
gsIrq();
|
|
}
|
|
|
|
static void GSRegHandlerFINISH(u32* data)
|
|
{
|
|
if (CSRw & 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 };
|
|
|
|
// ffx pal, ntsc, jap
|
|
#define GSHACK_FFX (ElfCRC==0xbb3d833a||ElfCRC==0xa39517ab||ElfCRC==0x6A4EFE60)
|
|
|
|
// 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];
|
|
|
|
#ifdef GSCAPTURE
|
|
u32 tempcount = 0;
|
|
#endif
|
|
|
|
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;
|
|
|
|
#ifdef GSCAPTURE
|
|
if( g_loggs && g_gstransnum == 19 && tempcount++ > g_gslimit ) {
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
pMem+= 4;
|
|
size--;
|
|
|
|
if(ptag->nloop == 0 ) {
|
|
if( path == 0 ) {
|
|
// ffx hack
|
|
if( GSHACK_FFX )
|
|
continue;
|
|
}
|
|
|
|
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);
|
|
g_path[path] = *ptag;
|
|
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);
|
|
g_path[path] = *ptag;
|
|
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 ) {
|
|
g_path[path] = *ptag;
|
|
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 GS_LOG
|
|
GS_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;
|
|
}
|
|
|
|
#ifdef GSCAPTURE
|
|
#define WRITINGDMA_TRANSFER(pMem, qwc) \
|
|
extern u32 g_loggs, g_gstransnum, g_gsfinalnum; \
|
|
if( !g_loggs || (g_loggs && g_gstransnum++ < g_gsfinalnum)) { \
|
|
GSgifTransfer3(pMem, qwc-GSgifTransferDummy(2, pMem, qwc)); \
|
|
} \
|
|
|
|
#else
|
|
#define WRITINGDMA_TRANSFER(pMem, qwc) GSgifTransfer3(pMem, qwc);
|
|
#endif
|
|
|
|
#define WRITERING_DMA(pMem, qwc) { \
|
|
if( CHECK_MULTIGS) { \
|
|
u8* pgsmem = GSRingBufCopy(pMem, (qwc)<<4, GS_RINGTYPE_P3); \
|
|
if( pgsmem != NULL ) { \
|
|
memcpy_amd(pgsmem, pMem, (qwc)<<4); \
|
|
\
|
|
pgsmem += (qwc)<<4; \
|
|
assert( pgsmem <= GS_RINGBUFFEREND ); \
|
|
if( pgsmem == GS_RINGBUFFEREND ) pgsmem = GS_RINGBUFFERBASE; \
|
|
InterlockedExchangePointer(&g_pGSWritePos, pgsmem); \
|
|
GSgifTransferDummy(2, pMem, qwc); \
|
|
} \
|
|
\
|
|
if( !CHECK_DUALCORE ) SetEvent(g_hGsEvent); \
|
|
} \
|
|
else { \
|
|
FreezeMMXRegs(1); \
|
|
FreezeXMMRegs(1); \
|
|
WRITINGDMA_TRANSFER(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);
|
|
|
|
SysPrintf("NULL GIFchain\n");
|
|
return -1;
|
|
}
|
|
|
|
WRITERING_DMA(pMem, qwc);
|
|
|
|
gif->madr+= qwc*16;
|
|
gif->qwc = 0;
|
|
return (qwc)*BIAS;
|
|
}
|
|
|
|
#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) & 0xC) == 0xC/* &&
|
|
(gif->tadr == psHu32(0xe050))*/) { // GIF MFIFO
|
|
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) { // STD == GIF
|
|
//SysPrintf("GS Stall Control Source = %x, Drain = %x\n", (psHu32(0xe000) >> 4) & 0x3, (psHu32(0xe000) >> 6) & 0x3);
|
|
|
|
if( gif->madr >= psHu32(DMAC_STADR) ) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
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;
|
|
// transfer interrupted, so continue
|
|
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++;
|
|
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+=1; // Add 1 cycles from the QW read for the tag
|
|
// Transfer dma tag if tte is set
|
|
if (gif->chcr & 0x40) {
|
|
//u32 temptag[4];
|
|
#ifdef GIF_LOG
|
|
//SysPrintf("GIF TTE: %x_%x\n", ptag[3], ptag[2]);
|
|
#endif
|
|
|
|
// temptag[2] = ptag[2];
|
|
// temptag[3] = ptag[3];
|
|
// GSgifTransfer3(temptag, 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
|
|
|
|
#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
|
|
|
|
done = hwDmacSrcChainWithStack(gif, id);
|
|
|
|
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 >= psHu32(DMAC_STADR) ) {
|
|
// stalled
|
|
psHu32(GIF_STAT)&= ~0x1f000E00; // OPH=0 | APATH=0
|
|
GSCSRr &= ~0xC000; //Clear FIFO stuff
|
|
GSCSRr |= 0x4000; //FIFO empty
|
|
prevcycles = cycles;
|
|
prevtag = ptag;
|
|
hwDmacIrq(13);
|
|
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;
|
|
//gif->madr = psHu32(DMAC_RBOR) + (gif->madr & psHu32(DMAC_RBSR));
|
|
|
|
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) * BIAS; /* guessing */
|
|
gif->qwc = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void mfifoGIFtransfer(int qwc) {
|
|
u32 *ptag;
|
|
int id;
|
|
int done = 0;
|
|
mfifocycles = 0;
|
|
#ifdef GIF_LOG
|
|
GIF_LOG("mfifoGIFtransfer qwc=0x%x\n", qwc);
|
|
#endif
|
|
if((gif->chcr & 0x100) == 0)SysPrintf("MFIFO GIF not ready %x\n", gif->chcr);
|
|
|
|
while (qwc > 0 && done == 0) { // Loop while Dn_CHCR.STR is 1
|
|
gif->tadr = psHu32(DMAC_RBOR) + (gif->tadr & psHu32(DMAC_RBSR));
|
|
ptag = (u32*)dmaGetAddr(gif->tadr);
|
|
|
|
id = (ptag[0] >> 28) & 0x7;
|
|
gif->qwc = (u16)ptag[0];
|
|
gif->madr = ptag[1];
|
|
mfifocycles += 2;
|
|
|
|
#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(gif->chcr & 0x40)
|
|
// GSgifTransfer3(ptag, 1);
|
|
|
|
switch (id) {
|
|
case 0: // refe
|
|
gif->tadr += 16;
|
|
qwc = 0;
|
|
INT(11,mfifocycles);
|
|
done = 1;
|
|
break;
|
|
|
|
case 1: // cnt
|
|
gif->madr = gif->tadr + 16;
|
|
qwc-= gif->qwc + 1;
|
|
// Set the taddr to the next tag
|
|
gif->tadr += 16 + (gif->qwc * 16);
|
|
break;
|
|
|
|
case 3: // ref
|
|
case 4: // refs
|
|
gif->tadr += 16;
|
|
qwc--;
|
|
break;
|
|
|
|
case 7: // end
|
|
gif->madr = gif->tadr + 16;
|
|
gif->tadr = gif->madr + (gif->qwc * 16);
|
|
qwc = 0;
|
|
INT(11,mfifocycles);
|
|
done = 1;
|
|
break;
|
|
}
|
|
|
|
if (mfifoGIFchain() == -1) {
|
|
break;
|
|
}
|
|
|
|
if ((gif->chcr & 0x80) && (ptag[0] >> 31)) {
|
|
#ifdef GIF_LOG
|
|
GIF_LOG("dmaIrq Set\n");
|
|
#endif
|
|
INT(11,mfifocycles);
|
|
//SysPrintf("mfifoGIFTransfer: dmaIrq Set\n");
|
|
//qwc = 0;
|
|
|
|
done = 1;
|
|
}
|
|
}
|
|
if(done == 0 && qwc == 0)hwDmacIrq(14);
|
|
/*if(qwc == 0 && gif->chcr & 0x100) {
|
|
hwDmacIrq(14);
|
|
return;
|
|
}*/
|
|
//INT(11,cycles);
|
|
//hwDmacIrq(2);
|
|
|
|
}
|
|
|
|
int gifMFIFOInterrupt() {
|
|
mfifocycles = 0;
|
|
gif->chcr &= ~0x100;
|
|
hwDmacIrq(DMAC_GIF);
|
|
|
|
return 1;
|
|
}
|
|
|
|
extern long pDsp;
|
|
DWORD WINAPI VuGSThreadProc(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 = 0x551B4000; // 0x55190000
|
|
SysPrintf("gsOpen done\n");
|
|
if (ret != 0) { SysMessage (_("Error Opening GS Plugin")); return -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) == 0 ) {
|
|
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:
|
|
GSgifTransfer1((u32*)(g_pGSRingPos+16), 0);
|
|
InterlockedExchangeAdd((PLONG)&g_pGSRingPos, 16 + ((tag>>16)<<4));
|
|
break;
|
|
|
|
case GS_RINGTYPE_P2:
|
|
GSgifTransfer2((u32*)(g_pGSRingPos+16), tag>>16);
|
|
InterlockedExchangeAdd((PLONG)&g_pGSRingPos, 16 + ((tag>>16)<<4));
|
|
break;
|
|
case GS_RINGTYPE_P3:
|
|
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;
|
|
|
|
#ifdef GS_ENABLE_CACHING
|
|
case GS_RINGTYPE_P2|GS_RINGTYPE_MEMREF:
|
|
case GS_RINGTYPE_P2|GS_RINGTYPE_MEMREF|GS_RINGTYPE_MEMNOFREE:
|
|
EnterCriticalSection(&g_PageAddrSection);
|
|
|
|
// read again since could have changed
|
|
tag = *(u32*)g_pGSRingPos;
|
|
|
|
GSgifTransfer2(*(u32**)(g_pGSRingPos+4), tag>>16);
|
|
|
|
if( ENABLE_GS_CACHING ) {
|
|
if( !(tag & GS_RINGTYPE_MEMNOFREE) ) {
|
|
GSFreeRingBuf(g_pGSRingPos);
|
|
}
|
|
else {
|
|
// using temp memory, so release
|
|
g_pGSTempReadPos = *(u8**)(g_pGSRingPos+4) + ((tag>>16)<<4);
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(&g_PageAddrSection);
|
|
|
|
#ifdef _RINGBUF_DEBUG
|
|
InterlockedExchangeAdd((PLONG)&g_pGSRingPos, 16 + ((tag>>16)<<4));
|
|
#else
|
|
InterlockedExchangeAdd((PLONG)&g_pGSRingPos, 16);
|
|
#endif
|
|
|
|
break;
|
|
case GS_RINGTYPE_P3|GS_RINGTYPE_MEMREF:
|
|
case GS_RINGTYPE_P3|GS_RINGTYPE_MEMREF|GS_RINGTYPE_MEMNOFREE:
|
|
|
|
EnterCriticalSection(&g_PageAddrSection);
|
|
|
|
// read again since could have changed
|
|
tag = *(u32*)g_pGSRingPos;
|
|
|
|
#ifdef _RINGBUF_DEBUG
|
|
assert( memcmp(*(u32**)(g_pGSRingPos+4), g_pGSRingPos+16, (tag>>16)*16) == 0 );
|
|
#endif
|
|
GSgifTransfer3(*(u32**)(g_pGSRingPos+4), tag>>16);
|
|
|
|
if( ENABLE_GS_CACHING ) {
|
|
if( !(tag & GS_RINGTYPE_MEMNOFREE) ) {
|
|
GSFreeRingBuf(g_pGSRingPos);
|
|
}
|
|
else {
|
|
// using temp memory, so release
|
|
g_pGSTempReadPos = *(u8**)(g_pGSRingPos+4) + ((tag>>16)<<4);
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(&g_PageAddrSection);
|
|
|
|
#ifdef _RINGBUF_DEBUG
|
|
InterlockedExchangeAdd((PLONG)&g_pGSRingPos, 16 + ((tag>>16)<<4));
|
|
#else
|
|
InterlockedExchangeAdd((PLONG)&g_pGSRingPos, 16);
|
|
#endif
|
|
break;
|
|
|
|
#endif // end GS_ENABLE_CACHING
|
|
|
|
case GS_RINGTYPE_VIFFIFO:
|
|
{
|
|
u64* pMem;
|
|
assert( vif1ch->madr == *(u32*)(g_pGSRingPos+4) );
|
|
assert( vif1ch->qwc == (tag>>16) );
|
|
|
|
pMem = (u64*)dmaGetAddr(vif1ch->madr);
|
|
|
|
if (pMem == NULL) {
|
|
psHu32(DMAC_STAT)|= 1<<15;
|
|
break;
|
|
}
|
|
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("VsGSThreadProc, bad packet\n");
|
|
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;
|
|
}
|
|
|
|
#undef GIFchain |