Summary of fixes

Games
- Resident Evil Dead Aim flickering graphics fixed.
- Flatout games should now boot everytime (instead of randomly)
- Sega Superstar Tennis flashing fixed
- Destruction Derby graphics fixed (NTSC confirmed, PAL unsure)
- Tenchu Fatal Shadows flickering textures fixed, Issue 748
- Spyro Hero's Tail should boot again, Issue 746

General Info
- General reworking of the GS paths with all paths prioritizing more correctly.
- XGKICK can stall if another GS transfer is in progress
- Major reworking of Path3 masking, could still be combined with normal Path3 transfers, but lets get it working first :P
- Taken in to account a few conditions which could have caused VIF to lock up/crash when stalling on ends.
- Unreversed GIF and SPR and VIF so its the normal way round
- all DMA paths should now resume correctly after being stopped by hardware
- GIF FIFO now actually transfers stuff :P
- VIF CMD's simulated by the length of the interrupts at the end.

Phew, i think that's everything :S

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@3274 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
refraction 2010-06-22 23:10:40 +00:00
parent 24ae022a74
commit 26fece9510
30 changed files with 1172 additions and 487 deletions

View File

@ -628,6 +628,13 @@ static __forceinline tDMA_TAG *SPRdmaGetAddr(u32 addr, bool write)
{
// if (addr & 0xf) { DMA_LOG("*PCSX2*: DMA address not 128bit aligned: %8.8x", addr); }
//For some reason Getaway references SPR Memory from itself using SPR0, oh well, let it i guess...
if((addr & 0x70000000) == 0x70000000)
{
return (tDMA_TAG*)&psS[addr & 0x3ff0];
}
// FIXME: Why??? DMA uses physical addresses
addr &= 0x1ffffff0;

View File

@ -129,7 +129,18 @@ void __fastcall WriteFIFO_page_4(u32 mem, const mem128_t *value)
psHu64(VIF0_FIFO + 8) = value[1];
vif0ch->qwc += 1;
bool ret = VIF0transfer((u32*)value, 4, true);
if(vif0.irqoffset != 0 && vif0.vifstalled == true) DevCon.Warning("Offset on VIF0 FIFO start!");
bool ret = VIF0transfer((u32*)value, 4);
if (vif0.cmd)
{
if(vif0.done == true && vif0ch->qwc == 0) vif0Regs->stat.VPS = VPS_WAITING;
}
else
{
vif0Regs->stat.VPS = VPS_IDLE;
}
pxAssertDev( ret, "vif stall code not implemented" );
}
@ -148,12 +159,23 @@ void __fastcall WriteFIFO_page_5(u32 mem, const mem128_t *value)
DevCon.Warning("writing to vif1 fifo when stalled");
vif1ch->qwc += 1;
bool ret = VIF1transfer((u32*)value, 4, false);
if(vif1.irqoffset != 0 && vif1.vifstalled == true) DevCon.Warning("Offset on VIF1 FIFO start!");
bool ret = VIF1transfer((u32*)value, 4);
if (vif1.cmd)
{
if(vif1.done == true && vif1ch->qwc == 0) vif1Regs->stat.VPS = VPS_WAITING;
}
else
{
vif1Regs->stat.VPS = VPS_IDLE;
}
pxAssertDev( ret, "vif stall code not implemented" );
}
// Dummy GIF-TAG Packet to Guarantee Count = 1
__aligned16 u32 nloop0_packet[4] = {0x8000, 0, 0, 0};
__aligned16 u32 nloop0_packet[4] = {0, 0, 0, 0};
void __fastcall WriteFIFO_page_6(u32 mem, const mem128_t *value)
{
@ -163,12 +185,23 @@ void __fastcall WriteFIFO_page_6(u32 mem, const mem128_t *value)
psHu64(GIF_FIFO) = value[0];
psHu64(GIF_FIFO + 8) = value[1];
nloop0_packet[0] = psHu32(GIF_FIFO);
nloop0_packet[1] = psHu32(GIF_FIFO + 4);
nloop0_packet[2] = psHu32(GIF_FIFO + 8);
nloop0_packet[3] = psHu32(GIF_FIFO + 12);
Registers::Freeze();
GetMTGS().PrepDataPacket(GIF_PATH_3, nloop0_packet, 1);
gifRegs->stat.APATH = GIF_APATH3;
GetMTGS().PrepDataPacket(GIF_PATH_3, nloop0_packet, 1, false);
u64* data = (u64*)GetMTGS().GetDataPacketPtr();
data[0] = value[0];
data[1] = value[1];
GetMTGS().SendDataPacket();
if(GSTransferStatus.PTH3 == PENDINGSTOP_MODE)
{
GSTransferStatus.PTH3 = STOPPED_MODE;
gifRegs->stat.APATH = GIF_APATH_IDLE;
if(gifRegs->stat.DIR == 0)gifRegs->stat.OPH = false;
}
Registers::Thaw();
}

View File

@ -59,7 +59,7 @@ void gsReset()
GetMTGS().ResetGS();
UpdateVSyncRate();
GSTransferStatus = (STOPPED_MODE<<4) | (STOPPED_MODE<<2) | STOPPED_MODE;
GSTransferStatus = (STOPPED_MODE<<8) | (STOPPED_MODE<<4) | STOPPED_MODE;
memzero(g_RealGSMem);
GSCSRr = 0x551B4000; // Set the FINISH bit to 1 for now
@ -98,17 +98,15 @@ void gsCSRwrite(u32 value)
GSCSRr = 0x551B4000; // Set the FINISH bit to 1 - GS is always at a finish state as we don't have a FIFO(saqib)
GSIMR = 0x7F00; //This is bits 14-8 thats all that should be 1
}
else if( value & 0x100 ) // FLUSH
if( value & 0x100 ) // FLUSH
{
// Our emulated GS has no FIFO, but if it did, it would flush it here...
//Console.WriteLn("GS_CSR FLUSH GS fifo: %x (CSRr=%x)", value, GSCSRr);
}
else
{
CSRw |= value & 0x1f;
GetMTGS().SendSimplePacket( GS_RINGTYPE_WRITECSR, CSRw, 0, 0 );
GSCSRr = ((GSCSRr&~value)&0x1f)|(GSCSRr&~0x1f);
}
}
@ -224,6 +222,17 @@ void __fastcall gsWrite64_page_01( u32 mem, const mem64_t* value )
switch( mem )
{
case 0x12001040: //busdir
gsWrite64_generic( mem, value );
//This is probably a complete hack, however writing to BUSDIR "should" start a transfer (Bleach Blade Battlers)
//Only problem is it kills killzone :( leaving it commented out for now.
//=========================================================================
//gifRegs->stat.OPH = true;
//=========================================================================
gifRegs->stat.DIR = (u32)value;
return;
case GS_CSR:
gsCSRwrite((u32)value[0]);
return;

View File

@ -157,7 +157,7 @@ enum GIF_PATH
GIF_PATH_3,
};
extern int GIFPath_ParseTag(GIF_PATH pathidx, const u8* pMem, u32 size);
extern int GIFPath_ParseTag(GIF_PATH pathidx, const u8* pMem, u32 size, bool TestOnly);
extern void GIFPath_Reset();
extern void GIFPath_Clear( GIF_PATH pathidx );
@ -252,8 +252,8 @@ public:
void WaitGS();
void ResetGS();
int PrepDataPacket( GIF_PATH pathidx, const u8* srcdata, u32 size );
int PrepDataPacket( GIF_PATH pathidx, const u32* srcdata, u32 size );
int PrepDataPacket( GIF_PATH pathidx, const u8* srcdata, u32 size, bool TestOnly );
int PrepDataPacket( GIF_PATH pathidx, const u32* srcdata, u32 size, bool TestOnly );
void SendDataPacket();
void SendGameCRC( u32 crc );
void WaitForOpen();

View File

@ -35,6 +35,11 @@ static u32 gscycles = 0, prevcycles = 0, mfifocycles = 0;
static u32 gifqwc = 0;
static bool gifmfifoirq = false;
//Just some temporary bits to store Path1 transfers if another is in progress.
u8 Path1Buffer[0x1000000];
u32 Path1WritePos = 0;
u32 Path1ReadPos = 0;
static __forceinline void clearFIFOstuff(bool full)
{
GSCSRr &= ~0xC000; //Clear FIFO stuff
@ -45,10 +50,51 @@ static __forceinline void clearFIFOstuff(bool full)
GSCSRr |= 0x4000; //FIFO empty
}
void gsPath1Interrupt()
{
//DevCon.Warning("Path1 flush W %x, R %x", Path1WritePos, Path1ReadPos);
if((gifRegs->stat.APATH == GIF_APATH_IDLE || gifRegs->stat.APATH == GIF_APATH1) && Path1WritePos > 0 && !gifRegs->stat.PSE)
{
Registers::Freeze();
u32 size = GetMTGS().PrepDataPacket(GIF_PATH_1, Path1Buffer + (Path1ReadPos*16), (Path1WritePos - Path1ReadPos), false);
u8* pDest = GetMTGS().GetDataPacketPtr();
//DevCon.Warning("Flush Size = %x", size);
gifRegs->stat.APATH = GIF_APATH1;
memcpy_aligned(pDest, Path1Buffer + (Path1ReadPos * 16), size*16);
GetMTGS().SendDataPacket();
Path1ReadPos += size;
if(Path1ReadPos == Path1WritePos)
{
Path1WritePos = Path1ReadPos = 0;
}
Registers::Thaw();
CPU_INT(28, 16); //Should be size * BIAS (probably) but Tony Hawk doesnt like this, probably to do with vif flush stalling
}
else
{
if(Path1WritePos == 0)
{
gifRegs->stat.P1Q = false;
gifRegs->stat.APATH = GIF_APATH_IDLE;
}
else
{
if(gifRegs->stat.PSE) DevCon.Warning("Path1 paused by GIF_CTRL");
CPU_INT(28, 16);
}
}
}
__forceinline void gsInterrupt()
{
GIF_LOG("gsInterrupt: %8.8x", cpuRegs.cycle);
if (!(gif->chcr.STR))
{
//Console.WriteLn("Eh? why are you still interrupting! chcr %x, qwc %x, done = %x", gif->chcr._u32, gif->qwc, done);
@ -56,11 +102,6 @@ __forceinline void gsInterrupt()
}
if (GSTransferStatus.PTH3 == STOPPED_MODE)
{
gifRegs->stat.clear_flags(GIF_STAT_APATH3);
}
if ((gif->qwc > 0) || (!gspath3done))
{
if (!dmacRegs->ctrl.DMAE)
@ -78,18 +119,16 @@ __forceinline void gsInterrupt()
gspath3done = false;
gscycles = 0;
gif->chcr.STR = false;
vif1Regs->stat.VGW = false;
if(GSTransferStatus.PTH3 == 3) GSTransferStatus.PTH3 = STOPPED_MODE;
gifRegs->stat.clear_flags(GIF_STAT_APATH3 | GIF_STAT_FQC);
//gifRegs->stat.OPH = false;
gifRegs->stat.clear_flags(GIF_STAT_FQC);
clearFIFOstuff(false);
hwDmacIrq(DMAC_GIF);
GIF_LOG("GIF DMA end");
//DevCon.Warning("GIF DMA end");
}
static u32 WRITERING_DMA(u32 *pMem, u32 qwc)
{
int size = GetMTGS().PrepDataPacket(GIF_PATH_3, pMem, qwc);
int size = GetMTGS().PrepDataPacket(GIF_PATH_3, pMem, qwc, false);
u8* pgsmem = GetMTGS().GetDataPacketPtr();
memcpy_aligned(pgsmem, pMem, size<<4);
@ -106,6 +145,7 @@ static u32 WRITERING_DMA(tDMA_TAG *pMem, u32 qwc)
int _GIFchain()
{
tDMA_TAG *pMem;
int qwc = 0;
pMem = dmaGetAddr(gif->madr, false);
if (pMem == NULL)
@ -120,7 +160,12 @@ int _GIFchain()
return -1;
}
return WRITERING_DMA(pMem, gif->qwc);
//in Intermittent Mode it enabled, IMAGE_MODE transfers are sliced.
if(gifRegs->stat.IMT && GSTransferStatus.PTH3 == IMAGE_MODE) qwc = min((int)gif->qwc, 8);
else qwc = gif->qwc;
return WRITERING_DMA(pMem, qwc);
}
static __forceinline void GIFchain()
@ -129,7 +174,7 @@ static __forceinline void GIFchain()
// qwc check now done outside this function
// Voodoocycles
// >> 2 so Drakan and Tekken 5 don't mess up in some PATH3 transfer. Cycles to interrupt were getting huge..
/*if (gif->qwc)*/ gscycles+= ( _GIFchain() >> 2 ); /* guessing */
/*if (gif->qwc)*/ gscycles+= ( _GIFchain() * BIAS); /* guessing */
Registers::Thaw();
}
@ -169,6 +214,43 @@ static __forceinline tDMA_TAG* ReadTag2()
return ptag;
}
bool CheckPaths(int Channel)
{
if(GSTransferStatus.PTH3 <= IMAGE_MODE && gifRegs->mode.IMT)
{
if((gifRegs->stat.P1Q == true || gifRegs->stat.P2Q == true) || (gifRegs->stat.APATH > GIF_APATH_IDLE && gifRegs->stat.APATH < GIF_APATH3))
{
if((vif1.cmd & 0x7f) != 0x51 || gifRegs->stat.P1Q == true)
{
if(gifRegs->stat.APATH == GIF_APATH3)
{
gifRegs->stat.APATH = GIF_APATH_IDLE;
}
gifRegs->stat.IP3 = true;
CPU_INT(DMAC_GIF, 16);
return false;
}
}
}
else if((GSTransferStatus.PTH3 >= IDLE_MODE))
{
//This should cover both scenarios, as DIRECTHL doesn't gain priority when image mode is running (PENDINGIMAGE_MODE == fininshed).
if((gifRegs->stat.P1Q == true || gifRegs->stat.P2Q == true) || (gifRegs->stat.APATH > GIF_APATH_IDLE && gifRegs->stat.APATH < GIF_APATH3))
{
if(gifRegs->stat.APATH == GIF_APATH3)
{
gifRegs->stat.APATH = GIF_APATH_IDLE;
}
gifRegs->stat.IP3 = true;
CPU_INT(DMAC_GIF, 16);
return false;
}
}
gifRegs->stat.IP3 = false;
return true;
}
void GIFdma()
{
tDMA_TAG *ptag;
@ -177,7 +259,8 @@ void GIFdma()
if (gifRegs->ctrl.PSE) // temporarily stop
{
Console.WriteLn("Gif dma temp paused?");
Console.WriteLn("Gif dma temp paused? (non MFIFO GIF)");
CPU_INT(DMAC_GIF, 16);
return;
}
@ -199,24 +282,14 @@ void GIFdma()
clearFIFOstuff(true);
gifRegs->stat.FQC = min((u16)0x10, gif->qwc);// FQC=31, hack ;) (for values of 31 that equal 16) [ used to be 0xE00; // APATH=3]
//Path2 gets priority in intermittent mode
if (GSTransferStatus.PTH1 != STOPPED_MODE || GSTransferStatus.PTH2 != STOPPED_MODE)
{
// We are in image mode doing DIRECTHL, Path 1 is in queue, and in intermittant mode.
//GIF_LOG("Waiting VU %x, PATH2 %x, GIFMODE %x Progress %x", gifRegs->stat.P1Q, (vif1.cmd & 0x7f), gifRegs->mode._u32, GSTransferStatus.PTH3);
gifRegs->stat.set_flags(GIF_STAT_P3Q);
CPU_INT(DMAC_GIF, 16);
return;
}
gifRegs->stat.clear_flags(GIF_STAT_P3Q);
gifRegs->stat.APATH = GIF_APATH3;
if (vif1Regs->mskpath3 || gifRegs->mode.M3R)
{
if (gif->qwc == 0)
{
if ((gif->chcr.MOD == CHAIN_MODE) && gif->chcr.STR)
{
//DevCon.Warning("GIF Reading Tag Masked MSK = %x", vif1Regs->mskpath3);
ptag = ReadTag();
gifRegs->stat.FQC = min((u16)0x10, gif->qwc);// FQC=31, hack ;) (for values of 31 that equal 16) [ used to be 0xE00; // APATH=3]
if (ptag == NULL) return;
@ -226,25 +299,41 @@ void GIFdma()
if (checkTieBit(ptag)) GIF_LOG("PATH3 MSK dmaIrq Set");
}
}
if (GSTransferStatus.PTH3 == STOPPED_MODE) /*|| (vif1Regs->stat._u32 |= VIF1_STAT_VGW) == 0*/
if (GSTransferStatus.PTH3 == STOPPED_MODE)
{
GIF_LOG("PTH3 MASK Paused by VIF");
vif1Regs->stat.VGW = false;
if (gif->qwc == 0) CPU_INT(DMAC_GIF, 16);
//DevCon.Warning("GIF Paused by Mask MSK = %x", vif1Regs->mskpath3);
if(gif->qwc == 0) gsInterrupt();
else gifRegs->stat.set_flags(GIF_STAT_P3Q);
return;
}
//gifRegs->stat.OPH = true;
gifRegs->stat.FQC = min((u16)0x10, gif->qwc);// FQC=31, hack ;) (for values of 31 that equal 16) [ used to be 0xE00; // APATH=3]
//Check with Path3 masking games
if (gif->qwc > 0) {
gifRegs->stat.set_flags(GIF_STAT_P3Q);
if(CheckPaths(DMAC_GIF) == false) return;
gifRegs->stat.clear_flags(GIF_STAT_P3Q);
GIF_LOG("PTH3 MASK Transferring");
GIFchain();
GIFchain();
/*if(GSTransferStatus.PTH3 == PENDINGSTOP_MODE && gifRegs->stat.APATH == GIF_APATH_IDLE)
{
GSTransferStatus.PTH3 = STOPPED_MODE;
}*/
}//else DevCon.WriteLn("GIFdma() case 1, but qwc = 0!"); //Don't do 0 GIFchain and then return
CPU_INT(DMAC_GIF, gscycles * BIAS);
CPU_INT(DMAC_GIF, gscycles);
return;
}
//gifRegs->stat.OPH = true;
// Transfer Dn_QWC from Dn_MADR to GIF
if ((gif->chcr.MOD == NORMAL_MODE) || (gif->qwc > 0)) // Normal Mode
{
@ -255,13 +344,18 @@ void GIFdma()
}
gifRegs->stat.FQC = min((u16)0x10, gif->qwc);// FQC=31, hack ;) (for values of 31 that equal 16) [ used to be 0xE00; // APATH=3]
//Check with Path3 masking games
//DevCon.Warning("GIF Transferring Normal/ChainQWC MSK = %x", vif1Regs->mskpath3);
if (gif->qwc > 0) {
gifRegs->stat.set_flags(GIF_STAT_P3Q);
if(CheckPaths(DMAC_GIF) == false) return;
gifRegs->stat.clear_flags(GIF_STAT_P3Q);
GIFchain(); //Transfers the data set by the switch
CPU_INT(DMAC_GIF, gscycles * BIAS);
CPU_INT(DMAC_GIF, gscycles);
return;
} else { //Else it really is a normal transfer and we want to quit, else it gets confused with chains
gspath3done = 1;
}
} else DevCon.Warning("GIF Normalmode or QWC going to invalid case? CHCR %x", gif->chcr);
//else DevCon.WriteLn("GIFdma() case 2, but qwc = 0!"); //Don't do 0 GIFchain and then return, fixes Dual Hearts
}
@ -270,6 +364,7 @@ void GIFdma()
{
ptag = ReadTag();
if (ptag == NULL) return;
//DevCon.Warning("GIF Reading Tag MSK = %x", vif1Regs->mskpath3);
GIF_LOG("gifdmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx tadr=%lx", ptag[1]._u32, ptag[0]._u32, gif->qwc, ptag->ID, gif->madr, gif->tadr);
gifRegs->stat.FQC = min((u16)0x10, gif->qwc);// FQC=31, hack ;) (for values of 31 that equal 16) [ used to be 0xE00; // APATH=3]
if (dmacRegs->ctrl.STD == STD_GIF)
@ -290,65 +385,48 @@ void GIFdma()
}
checkTieBit(ptag);
/*if(gif->qwc == 0)
{
gsInterrupt();
return;
}*/
}
prevcycles = 0;
if ((!gspath3done) && (gif->qwc == 0))
{
ptag = dmaGetAddr(gif->tadr, false); //Set memory pointer to TADR
gif->unsafeTransfer(ptag);
gif->madr = ptag[1]._u32;
gspath3done = hwDmacSrcChainWithStack(gif, ptag->ID);
checkTieBit(ptag);
GIF_LOG("gifdmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx tadr=%lx", ptag[1]._u32, ptag[0]._u32, gif->qwc, ptag->ID, gif->madr, gif->tadr);
CPU_INT(DMAC_GIF, gscycles * BIAS);
}
else
{
CPU_INT(DMAC_GIF, gscycles * BIAS);
gscycles = 0;
}
gifRegs->stat.FQC = min((u16)0x10, gif->qwc);// FQC=31, hack ;) (for values of 31 that equal 16) [ used to be 0xE00; // APATH=3]
CPU_INT(DMAC_GIF, gscycles);
gifRegs->stat.FQC = min((u16)0x10, gif->qwc);// FQC=31, hack ;) (for values of 31 that equal 16) [ used to be 0xE00; // OPH=1 | APATH=3]
}
void dmaGIF()
{
//We used to add wait time for the buffer to fill here, fixing some timing problems in path 3 masking
//It takes the time of 24 QW for the BUS to become ready - The Punisher And Streetball
GIF_LOG("dmaGIFstart chcr = %lx, madr = %lx, qwc = %lx\n tadr = %lx, asr0 = %lx, asr1 = %lx", gif->chcr._u32, gif->madr, gif->qwc, gif->tadr, gif->asr0, gif->asr1);
//DevCon.Warning("dmaGIFstart chcr = %lx, madr = %lx, qwc = %lx\n tadr = %lx, asr0 = %lx, asr1 = %lx", gif->chcr._u32, gif->madr, gif->qwc, gif->tadr, gif->asr0, gif->asr1);
//GSTransferStatus.PTH3 = STOPPED_MODE;
gspath3done = false; // For some reason this doesn't clear? So when the system starts the thread, we will clear it :)
gifRegs->stat.P3Q = true;
gifRegs->stat.FQC |= 0x10; // hack ;)
if (gif->chcr.MOD == NORMAL_MODE) { //Else it really is a normal transfer and we want to quit, else it gets confused with chains
gspath3done = true;
}
clearFIFOstuff(true);
if(gif->chcr.MOD == CHAIN_MODE && gif->qwc > 0)
{
//DevCon.Warning(L"GIF QWC on Chain " + gif->chcr.desc());
if(((gif->chcr.TAG >> 12) & 0x7) == 0x0 || ((gif->chcr.TAG >> 12) & 0x7) == 0x7)
{
gspath3done = true;
}
}
if (dmacRegs->ctrl.MFD == MFD_GIF) // GIF MFIFO
{
//Console.WriteLn("GIF MFIFO");
gifMFIFOInterrupt();
return;
}
if ((gif->qwc == 0) && (gif->chcr.MOD != NORMAL_MODE))
{
tDMA_TAG* ptag = ReadTag2();
GIF_LOG("gifdmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx tadr=%lx", ptag[1]._u32, ptag[0]._u32, gif->qwc, ptag->ID, gif->madr, gif->tadr);
checkTieBit(ptag);
GIFdma();
return;
}
//Halflife sets a QWC amount in chain mode, no tadr set.
if (gif->qwc > 0) gspath3done = true;
if(gif->chcr.MOD == CHAIN_MODE && gif->qwc > 0) DevCon.Warning(L"GIF QWC on Chain " + gif->chcr.desc());
}
GIFdma();
}
@ -447,7 +525,12 @@ void mfifoGIFtransfer(int qwc)
gifempty = false;
}
GIF_LOG("mfifoGIFtransfer %x madr %x, tadr %x", gif->chcr._u32, gif->madr, gif->tadr);
if (gifRegs->ctrl.PSE) // temporarily stop
{
Console.WriteLn("Gif dma temp paused?");
CPU_INT(11, 16);
return;
}
if (gif->qwc == 0)
{
@ -540,11 +623,7 @@ void gifMFIFOInterrupt()
gifRegs->stat.APATH = GIF_APATH_IDLE;
}
if ((spr0->chcr.STR) && (spr0->qwc == 0))
{
spr0->chcr.STR = false;
hwDmacIrq(DMAC_FROM_SPR);
}
if(CheckPaths(11) == false) return;
if (!(gif->chcr.STR))
{
@ -553,13 +632,6 @@ void gifMFIFOInterrupt()
return;
}
if ((gifRegs->stat.P1Q || (vif1.cmd & 0x7f) == 0x50) && gifRegs->mode.IMT && GSTransferStatus.PTH3 == IMAGE_MODE) //Path2 gets priority in intermittent mode
{
//GIF_LOG("Waiting VU %x, PATH2 %x, GIFMODE %x Progress %x", psHu32(GIF_STAT) & 0x100, (vif1.cmd & 0x7f), psHu32(GIF_MODE), GSTransferStatus.PTH3);
CPU_INT(11,mfifocycles);
return;
}
if (!(gifstate & GIF_STATE_STALL))
{
if (gifqwc <= 0)

View File

@ -26,17 +26,20 @@ enum gifstate_t
enum GSTransferModes //0 = Image Mode (DirectHL), 1 = transferring, 2 = Stopped at End of Packet
{
IMAGE_MODE = 0,
TRANSFER_MODE = 1,
STOPPED_MODE = 2
PENDINGIMAGE_MODE = 0,
IMAGE_MODE = 1,
TRANSFER_MODE = 2,
PENDINGSTOP_MODE = 3,
IDLE_MODE = 4,
STOPPED_MODE = 5
};
union tGSTransferStatus {
struct {
u32 PTH1 : 2; // Resets Vif(0/1) when written.
u32 PTH2 : 2; // Causes a Forcebreak to Vif((0/1) when true. (Stall)
u32 PTH3 : 2; // Stops after the end of the Vifcode in progress when true. (Stall)
u32 reserved : 26;
u32 PTH1 : 4; // Resets Vif(0/1) when written.
u32 PTH2 : 4; // Causes a Forcebreak to Vif((0/1) when true. (Stall)
u32 PTH3 : 4; // Stops after the end of the Vifcode in progress when true. (Stall)
u32 reserved : 20;
};
u32 _u32;
@ -285,4 +288,9 @@ extern void dmaGIF();
extern void mfifoGIFtransfer(int qwc);
extern void gifMFIFOInterrupt();
//Just some temporary bits to store Path1 transfers if another is in progress.
extern void gsPath1Interrupt();
extern u8 Path1Buffer[0x1000000];
extern u32 Path1WritePos;
extern u32 Path1ReadPos;
#endif

View File

@ -75,13 +75,15 @@ void hwReset()
__forceinline void intcInterrupt()
{
if ((cpuRegs.CP0.n.Status.val & 0x400) != 0x400) return;
if ((psHu32(INTC_STAT)) == 0) {
DevCon.Warning("*PCSX2*: intcInterrupt already cleared");
//DevCon.Warning("*PCSX2*: intcInterrupt already cleared");
return;
}
if ((psHu32(INTC_STAT) & psHu32(INTC_MASK)) == 0) return;
if ((psHu32(INTC_STAT) & psHu32(INTC_MASK)) == 0)
{
//DevCon.Warning("*PCSX2*: No valid interrupt INTC_MASK: %x INTC_STAT: %x", psHu32(INTC_MASK), psHu32(INTC_STAT));
return;
}
HW_LOG("intcInterrupt %x", psHu32(INTC_STAT) & psHu32(INTC_MASK));
if(psHu32(INTC_STAT) & 0x2){
@ -94,13 +96,18 @@ __forceinline void intcInterrupt()
__forceinline void dmacInterrupt()
{
if ((cpuRegs.CP0.n.Status.val & 0x10807) != 0x10801) return;
if( ((psHu16(DMAC_STAT + 2) & psHu16(DMAC_STAT)) == 0 ) &&
( psHu16(DMAC_STAT) & 0x8000) == 0 ) return;
if (!(dmacRegs->ctrl.DMAE)) return;
( psHu16(DMAC_STAT) & 0x8000) == 0 )
{
//DevCon.Warning("No valid DMAC interrupt MASK %x STAT %x", psHu16(DMAC_STAT+2), psHu16(DMAC_STAT));
return;
}
if (!(dmacRegs->ctrl.DMAE) || psHu8(DMAC_ENABLER+2) == 1)
{
//DevCon.Warning("DMAC Suspended or Disabled on interrupt");
return;
}
HW_LOG("dmacInterrupt %x", (psHu16(DMAC_STAT + 2) & psHu16(DMAC_STAT) |
psHu16(DMAC_STAT) & 0x8000));
@ -110,13 +117,13 @@ __forceinline void dmacInterrupt()
void hwIntcIrq(int n)
{
psHu32(INTC_STAT) |= 1<<n;
cpuTestINTCInts();
if(psHu32(INTC_MASK) & (1<<n))cpuTestINTCInts();
}
void hwDmacIrq(int n)
{
psHu32(DMAC_STAT) |= 1<<n;
cpuTestDMACInts();
if(psHu16(DMAC_STAT+2) & (1<<n))cpuTestDMACInts();
}
// Write 'size' bytes to memory address 'addr' from 'data'.

View File

@ -381,7 +381,9 @@ mem32_t __fastcall hwRead32_generic(u32 mem)
// It'll all optimize to ziltch in public release builds.
#ifdef PCSX2_DEVBUILD
case 0x03:
if((mem & 0xfff) < 0x800) break;
if(masked_mem >= 0x3800) HW_LOG("VIF%x Register Read32 at 0x%x, value=0x%x", (masked_mem < 0x3c00) ? 0 : 1, mem, psHu32(mem) );
else HW_LOG("GIF Register Read32 at 0x%x, value=0x%x", mem, psHu32(mem) );
break;
case 0x04:
case 0x05:
case 0x06:

View File

@ -75,8 +75,19 @@ static __forceinline void DmaExec8( void (*func)(), u32 mem, u8 value )
if(value == 0)
{
//DevCon.Warning(L"8bit %s DMA Stopped on Suspend", ChcrName(mem & ~0xf));
if(ChannelNumber(mem & ~0xf) == 1)
{
cpuClearInt( 10 );
QueuedDMA._u16 &= ~(1 << 10); //Clear any queued DMA requests for this channel
}
else if(ChannelNumber(mem & ~0xf) == 2)
{
cpuClearInt( 11 );
QueuedDMA._u16 &= ~(1 << 11); //Clear any queued DMA requests for this channel
}
cpuClearInt( ChannelNumber(mem & ~0xf) );
QueuedDMA._u16 &= ~(1 << ChannelNumber(mem & ~0xf));
QueuedDMA._u16 &= ~(1 << ChannelNumber(mem & ~0xf)); //Clear any queued DMA requests for this channel;
}
//Here we update the CHCR STR (Busy) bit, we don't touch anything else.
reg->chcr.STR = value;
@ -93,8 +104,20 @@ static __forceinline void DmaExec8( void (*func)(), u32 mem, u8 value )
//DevCon.Warning(L"8bit Force Stopping %s (Current CHCR %x) while DMA active", ChcrName(mem & ~0xf), reg->chcr._u32, value);
reg->chcr.STR = value;
//We need to clear any existing DMA loops that are in progress else they will continue!
cpuClearInt( ChannelNumber(mem&~0xf) );
QueuedDMA._u16 &= ~(1 << ChannelNumber(mem&~0xf)); //Clear any queued DMA requests for this channel
if(ChannelNumber(mem & ~0xf) == 1)
{
cpuClearInt( 10 );
QueuedDMA._u16 &= ~(1 << 10); //Clear any queued DMA requests for this channel
}
else if(ChannelNumber(mem & ~0xf) == 2)
{
cpuClearInt( 11 );
QueuedDMA._u16 &= ~(1 << 11); //Clear any queued DMA requests for this channel
}
cpuClearInt( ChannelNumber(mem & ~0xf) );
QueuedDMA._u16 &= ~(1 << ChannelNumber(mem & ~0xf)); //Clear any queued DMA requests for this channel
}
//else DevCon.Warning(L"8bit Attempted to stop %s DMA without suspend, ignoring", ChcrName(mem & ~0xf));
return;
@ -132,6 +155,17 @@ static __forceinline void DmaExec16( void (*func)(), u32 mem, u16 value )
if(chcr.STR == 0)
{
//DevCon.Warning(L"16bit %s DMA Stopped on Suspend", ChcrName(mem));
if(ChannelNumber(mem) == 1)
{
cpuClearInt( 10 );
QueuedDMA._u16 &= ~(1 << 10); //Clear any queued DMA requests for this channel
}
else if(ChannelNumber(mem) == 2)
{
cpuClearInt( 11 );
QueuedDMA._u16 &= ~(1 << 11); //Clear any queued DMA requests for this channel
}
cpuClearInt( ChannelNumber(mem) );
QueuedDMA._u16 &= ~(1 << ChannelNumber(mem)); //Clear any queued DMA requests for this channel
}
@ -150,6 +184,18 @@ static __forceinline void DmaExec16( void (*func)(), u32 mem, u16 value )
//DevCon.Warning(L"16bit Force Stopping %s (Current CHCR %x) while DMA active", ChcrName(mem), reg->chcr._u32, chcr._u32);
reg->chcr.STR = 0;
//We need to clear any existing DMA loops that are in progress else they will continue!
if(ChannelNumber(mem) == 1)
{
cpuClearInt( 10 );
QueuedDMA._u16 &= ~(1 << 10); //Clear any queued DMA requests for this channel
}
else if(ChannelNumber(mem) == 2)
{
cpuClearInt( 11 );
QueuedDMA._u16 &= ~(1 << 11); //Clear any queued DMA requests for this channel
}
cpuClearInt( ChannelNumber(mem) );
QueuedDMA._u16 &= ~(1 << ChannelNumber(mem)); //Clear any queued DMA requests for this channel
}
@ -189,8 +235,19 @@ static void DmaExec( void (*func)(), u32 mem, u32 value )
if(chcr.STR == 0)
{
//DevCon.Warning(L"32bit %s DMA Stopped on Suspend", ChcrName(mem));
QueuedDMA._u16 &= ~(1 << ChannelNumber(mem)); //Clear any queued DMA requests for this channel
if(ChannelNumber(mem) == 1)
{
cpuClearInt( 10 );
QueuedDMA._u16 &= ~(1 << 10); //Clear any queued DMA requests for this channel
}
else if(ChannelNumber(mem) == 2)
{
cpuClearInt( 11 );
QueuedDMA._u16 &= ~(1 << 11); //Clear any queued DMA requests for this channel
}
cpuClearInt( ChannelNumber(mem) );
QueuedDMA._u16 &= ~(1 << ChannelNumber(mem)); //Clear any queued DMA requests for this channel
}
//Sanity Check for possible future bug fix0rs ;p
//Spams on Persona 4 opening.
@ -211,6 +268,18 @@ static void DmaExec( void (*func)(), u32 mem, u32 value )
//DevCon.Warning(L"32bit Force Stopping %s (Current CHCR %x) while DMA active", ChcrName(mem), reg->chcr._u32, chcr._u32);
reg->chcr.STR = 0;
//We need to clear any existing DMA loops that are in progress else they will continue!
if(ChannelNumber(mem) == 1)
{
cpuClearInt( 10 );
QueuedDMA._u16 &= ~(1 << 10); //Clear any queued DMA requests for this channel
}
else if(ChannelNumber(mem) == 2)
{
cpuClearInt( 11 );
QueuedDMA._u16 &= ~(1 << 11); //Clear any queued DMA requests for this channel
}
cpuClearInt( ChannelNumber(mem) );
QueuedDMA._u16 &= ~(1 << ChannelNumber(mem)); //Clear any queued DMA requests for this channel
}
@ -282,6 +351,31 @@ void hwWrite8(u32 mem, u8 value)
case RCNT3_MODE + 1: rcntWmode(3, (counters[3].modeval & 0xff) | value << 8); break;
case RCNT3_TARGET: rcntWtarget(3, value); break;
case GIF_CTRL:
psHu32(mem) = value & 0x8;
DevCon.Warning("GIFCTRL 8 = %x", value);
if (value & 0x1)
gsGIFReset();
if ( value & 8 )
gifRegs->stat.PSE = true;
else
gifRegs->stat.PSE = false;
break;
case GIF_MODE:
{
// need to set GIF_MODE (hamster ball)
gifRegs->mode.write(value);
// set/clear bits 0 and 2 as per the GIF_MODE value.
const u32 bitmask = GIF_MODE_M3R | GIF_MODE_IMT;
psHu32(GIF_STAT) &= ~bitmask;
psHu32(GIF_STAT) |= (u32)value & bitmask;
if(value & GIF_MODE_M3R) DevCon.Warning("8bit GIFMODE M3R write %x", value);
//if(value & GIF_MODE_IMT) DevCon.Warning("8bit GIFMODE INT write %x", value);
}
break;
case SIO_TXFIFO:
{
// Terminate lines on CR or full buffers, and ignore \n's if the string contents
@ -394,6 +488,13 @@ void hwWrite8(u32 mem, u8 value)
psHu8(mem) = value;
break;
case DMAC_STAT:
case DMAC_STAT + 1:
case DMAC_STAT + 2:
case DMAC_STAT + 3:
DevCon.Warning("8bit dmac stat! %x", mem);
break;
case DMAC_ENABLEW + 2:
oldvalue = psHu8(DMAC_ENABLEW + 2);
psHu8(DMAC_ENABLEW + 2) = value;
@ -403,6 +504,18 @@ void hwWrite8(u32 mem, u8 value)
if (!QueuedDMA.empty()) StartQueuedDMA();
}
break;
case DMAC_CTRL+2:
oldvalue = psHu8(mem);
if ((oldvalue & 0x3) != (value & 0x3))
{
DevCon.Warning("8 Stall Source Changed to %x", (value & 0x30) >> 4);
}
if ((oldvalue & 0xC) != (value & 0xC))
{
DevCon.Warning("8 Stall Destination Changed to %x", (value & 0xC0) >> 4);
}
psHu8(mem) = value;
break;
case SBUS_F200: // SIF(?)
psHu8(mem) = value;
@ -474,6 +587,32 @@ __forceinline void hwWrite16(u32 mem, u16 value)
case RCNT3_MODE: rcntWmode(3, value); break;
case RCNT3_TARGET: rcntWtarget(3, value); break;
case GIF_CTRL:
psHu32(mem) = value & 0x8;
DevCon.Warning("GIFCTRL 16 %x", value);
if (value & 0x1)
gsGIFReset();
if ( value & 8 )
gifRegs->stat.PSE = true;
else
gifRegs->stat.PSE = false;
break;
case GIF_MODE:
{
// need to set GIF_MODE (hamster ball)
gifRegs->mode.write(value);
// set/clear bits 0 and 2 as per the GIF_MODE value.
const u32 bitmask = GIF_MODE_M3R | GIF_MODE_IMT;
psHu32(GIF_STAT) &= ~bitmask;
psHu32(GIF_STAT) |= (u32)value & bitmask;
if(value & GIF_MODE_M3R) DevCon.Warning("16bit GIFMODE M3R write %x", value);
//if(value & GIF_MODE_IMT) DevCon.Warning("16bit GIFMODE INT write %x", value);
}
break;
case D0_CHCR: // dma0 - vif0
DMA_LOG("VIF0dma %lx", value);
DmaExec16(dmaVIF0, mem, value);
@ -667,6 +806,10 @@ __forceinline void hwWrite16(u32 mem, u16 value)
//DevCon.Warning(L"16bit CHCR TAG changed to %x from %x on %s DMA", value, psHu32(mem), ChcrName(mem & ~0xf));
psHu16(mem) = value;
break;
case DMAC_STAT:
case DMAC_STAT + 2:
DevCon.Warning("16bit dmac stat! %x", mem);
break;
case DMAC_ENABLEW + 2:
oldvalue = psHu8(DMAC_ENABLEW + 2);
@ -677,7 +820,18 @@ __forceinline void hwWrite16(u32 mem, u16 value)
if (!QueuedDMA.empty()) StartQueuedDMA();
}
break;
case DMAC_CTRL:
oldvalue = psHu16(mem);
if ((oldvalue & 0x30) != (value & 0x30))
{
DevCon.Warning("Stall Source Changed to %x", (value & 0x30) >> 4);
}
if ((oldvalue & 0xC0) != (value & 0xC0))
{
DevCon.Warning("Stall Destination Changed to %x", (value & 0xC0) >> 4);
}
psHu16(mem) = value;
break;
case SIO_ISR:
case SIO_ISR + 2:
case 0x1000f410:
@ -786,7 +940,8 @@ void __fastcall hwWrite32_page_03( u32 mem, u32 value )
if (value & 0x1)
gsGIFReset();
else if ( value & 8 )
if ( value & 8 )
gifRegs->stat.PSE = true;
else
gifRegs->stat.PSE = false;
@ -866,6 +1021,14 @@ void __fastcall hwWrite32_page_0E( u32 mem, u32 value )
{
if (!QueuedDMA.empty()) StartQueuedDMA();
}
if ((oldvalue & 0x30) != (value & 0x30))
{
DevCon.Warning("Stall Source Changed to %x", (value & 0x30) >> 4);
}
if ((oldvalue & 0xC0) != (value & 0xC0))
{
DevCon.Warning("Stall Destination Changed to %x", (value & 0xC0) >> 4);
}
break;
}
@ -1127,6 +1290,14 @@ void __fastcall hwWrite64_page_0E( u32 mem, const mem64_t* srcval )
{
if (!QueuedDMA.empty()) StartQueuedDMA();
}
if ((oldvalue & 0x30) != (value & 0x30))
{
DevCon.Warning("Stall Source Changed to %x", (value & 0x30) >> 4);
}
if ((oldvalue & 0xC0) != (value & 0xC0))
{
DevCon.Warning("Stall Destination Changed to %x", (value & 0xC0) >> 4);
}
break;
}

View File

@ -197,12 +197,14 @@ void psxDma9(u32 madr, u32 bcr, u32 chcr)
sif0.iop.busy = true;
psHu32(SBUS_F240) |= 0x2000;
if (sif0.ee.busy)
{
/*if (sif0.ee.busy)
{*/
XMMRegisters::Freeze();
SIF0Dma();
psHu32(SBUS_F240) &= ~0x20;
psHu32(SBUS_F240) &= ~0x2000;
}
XMMRegisters::Thaw();
//}
}
void psxDma10(u32 madr, u32 bcr, u32 chcr)
@ -212,15 +214,15 @@ void psxDma10(u32 madr, u32 bcr, u32 chcr)
sif1.iop.busy = true;
psHu32(SBUS_F240) |= 0x4000;
if (sif1.ee.busy)
{
/*if (sif1.ee.busy)
{*/
XMMRegisters::Freeze();
SIF1Dma();
psHu32(SBUS_F240) &= ~0x40;
psHu32(SBUS_F240) &= ~0x100;
psHu32(SBUS_F240) &= ~0x4000;
XMMRegisters::Thaw();
}
//}
}
/* psxDma11 & psxDma 12 are in IopSio2.cpp, along with the appropriate interrupt functions. */

View File

@ -594,9 +594,9 @@ void SysMtgsThread::SendDataPacket()
//m_PacketLocker.Release();
}
int SysMtgsThread::PrepDataPacket( GIF_PATH pathidx, const u32* srcdata, u32 size )
int SysMtgsThread::PrepDataPacket( GIF_PATH pathidx, const u32* srcdata, u32 size, bool TestOnly )
{
return PrepDataPacket( pathidx, (u8*)srcdata, size );
return PrepDataPacket( pathidx, (u8*)srcdata, size, TestOnly );
}
#ifdef PCSX2_GSRING_TX_STATS
@ -614,7 +614,7 @@ static u32 ringtx_inf_s[32];
// around VU memory instead of having buffer overflow...
// Parameters:
// size - size of the packet data, in smd128's
int SysMtgsThread::PrepDataPacket( GIF_PATH pathidx, const u8* srcdata, u32 size )
int SysMtgsThread::PrepDataPacket( GIF_PATH pathidx, const u8* srcdata, u32 size, bool TestOnly )
{
//m_PacketLocker.Acquire();
@ -674,9 +674,10 @@ int SysMtgsThread::PrepDataPacket( GIF_PATH pathidx, const u8* srcdata, u32 size
pxAssert( size < RingBufferSize );
pxAssert( writepos < RingBufferSize );
m_packet_size = GIFPath_ParseTag(pathidx, srcdata, size);
m_packet_size = GIFPath_ParseTag(pathidx, srcdata, size, TestOnly);
if( TestOnly == true) return m_packet_size;
size = m_packet_size + 1; // takes into account our command qword.
if( writepos + size < RingBufferSize )
{
// generic gs wait/stall.

View File

@ -294,8 +294,9 @@ static __forceinline void _cpuTestInterrupts()
/* These are 'pcsx2 interrupts', they handle asynchronous stuff
that depends on the cycle timings */
TESTINT(1, vif1Interrupt);
TESTINT(2, gsInterrupt);
TESTINT(28, gsPath1Interrupt);
TESTINT(1, vif1Interrupt);
TESTINT(2, gsInterrupt);
TESTINT(5, EEsif0Interrupt);
TESTINT(6, EEsif1Interrupt);
@ -351,10 +352,12 @@ static __forceinline void _cpuTestPERF()
// them out. Exceptions while the exception handler is active (EIE), or exceptions of any
// level other than 0 are ignored here.
static bool cpuIntsEnabled()
static bool cpuIntsEnabled(int Interrupt)
{
int IntType = cpuRegs.CP0.n.Status.val & Interrupt; //Choose either INTC or DMAC, depending on what called it
return cpuRegs.CP0.n.Status.b.EIE && cpuRegs.CP0.n.Status.b.IE &&
!cpuRegs.CP0.n.Status.b.EXL && (cpuRegs.CP0.n.Status.b.ERL == 0);
!cpuRegs.CP0.n.Status.b.EXL && (cpuRegs.CP0.n.Status.b.ERL == 0) && Interrupt;
}
// if cpuRegs.cycle is greater than this cycle, should check cpuBranchTest for updates
@ -480,18 +483,15 @@ __forceinline void _cpuBranchTest_Shared()
// exceptions.
//if ((cpuRegs.CP0.n.Status.val & 0x10007) == 0x10001)
if( cpuIntsEnabled() )
{
TESTINT(30, intcInterrupt);
TESTINT(31, dmacInterrupt);
}
if( cpuIntsEnabled(0x400) ) TESTINT(30, intcInterrupt);
if( cpuIntsEnabled(0x800) ) TESTINT(31, dmacInterrupt);
}
__releaseinline void cpuTestINTCInts()
{
if( cpuRegs.interrupt & (1 << 30) ) return;
//if( (cpuRegs.CP0.n.Status.val & 0x10407) != 0x10401 ) return;
if( !cpuIntsEnabled() ) return;
if( !cpuIntsEnabled(0x400) ) return;
if( (psHu32(INTC_STAT) & psHu32(INTC_MASK)) == 0 ) return;
cpuRegs.interrupt|= 1 << 30;
@ -512,7 +512,8 @@ __releaseinline void cpuTestINTCInts()
__forceinline void cpuTestDMACInts()
{
if ( cpuRegs.interrupt & (1 << 31) ) return;
if ((cpuRegs.CP0.n.Status.val & 0x10807) != 0x10801) return;
if( !cpuIntsEnabled(0x800) ) return;
if ( ( (psHu16(0xe012) & psHu16(0xe010)) == 0) &&
( (psHu16(0xe010) & 0x8000) == 0) ) return;

View File

@ -81,12 +81,12 @@ int _SPR0chain()
spr0->sadr += spr0->qwc << 4;
return (spr0->qwc) * BIAS; // bus is 1/2 the ee speed
return (spr0->qwc); // bus is 1/2 the ee speed
}
__forceinline void SPR0chain()
{
_SPR0chain();
CPU_INT(DMAC_FROM_SPR, _SPR0chain() / BIAS);
spr0->qwc = 0;
}
@ -102,6 +102,8 @@ void _SPR0interleave()
SPR_LOG("SPR0 interleave size=%d, tqwc=%d, sqwc=%d, addr=%lx sadr=%lx",
spr0->qwc, tqwc, sqwc, spr0->madr, spr0->sadr);
CPU_INT(DMAC_FROM_SPR, qwc / BIAS);
while (qwc > 0)
{
spr0->qwc = std::min(tqwc, qwc);
@ -150,12 +152,11 @@ static __forceinline void _dmaSPR0()
case CHAIN_MODE:
{
tDMA_TAG *ptag;
bool done = FALSE;
bool done = false;
if (spr0->qwc > 0)
{
SPR0chain();
spr0finished = true;
return;
}
// Destination Chain Mode
@ -198,13 +199,6 @@ static __forceinline void _dmaSPR0()
}
spr0finished = done;
if (!done)
{
ptag = (tDMA_TAG*)&psSu32(spr0->sadr); //Set memory pointer to SADR
CPU_INT(DMAC_FROM_SPR, /*ptag[0].QWC / BIAS*/ 4 ); // the lower 16bits of the tag / BIAS);
return;
}
SPR_LOG("spr0 dmaChain complete %8.8x_%8.8x size=%d, id=%d, addr=%lx spr=%lx",
ptag[1]._u32, ptag[0]._u32, spr0->qwc, ptag->ID, spr0->madr);
break;
@ -220,37 +214,39 @@ static __forceinline void _dmaSPR0()
void SPRFROMinterrupt()
{
_dmaSPR0();
if(mfifotransferred != 0)
if (!spr0finished || spr0->qwc > 0)
{
switch (dmacRegs->ctrl.MFD)
_dmaSPR0();
if(mfifotransferred != 0)
{
case MFD_VIF1: // Most common case.
switch (dmacRegs->ctrl.MFD)
{
if ((spr0->madr & ~dmacRegs->rbsr.RMSK) != dmacRegs->rbor.ADDR) Console.WriteLn("VIF MFIFO Write outside MFIFO area");
spr0->madr = dmacRegs->rbor.ADDR + (spr0->madr & dmacRegs->rbsr.RMSK);
//Console.WriteLn("mfifoVIF1transfer %x madr %x, tadr %x", vif1ch->chcr._u32, vif1ch->madr, vif1ch->tadr);
mfifoVIF1transfer(mfifotransferred);
mfifotransferred = 0;
if (vif1ch->chcr.STR) return;
break;
case MFD_VIF1: // Most common case.
{
if ((spr0->madr & ~dmacRegs->rbsr.RMSK) != dmacRegs->rbor.ADDR) Console.WriteLn("VIF MFIFO Write outside MFIFO area");
spr0->madr = dmacRegs->rbor.ADDR + (spr0->madr & dmacRegs->rbsr.RMSK);
//Console.WriteLn("mfifoVIF1transfer %x madr %x, tadr %x", vif1ch->chcr._u32, vif1ch->madr, vif1ch->tadr);
mfifoVIF1transfer(mfifotransferred);
mfifotransferred = 0;
break;
}
case MFD_GIF:
{
if ((spr0->madr & ~dmacRegs->rbsr.RMSK) != dmacRegs->rbor.ADDR) Console.WriteLn("GIF MFIFO Write outside MFIFO area");
spr0->madr = dmacRegs->rbor.ADDR + (spr0->madr & dmacRegs->rbsr.RMSK);
//Console.WriteLn("mfifoGIFtransfer %x madr %x, tadr %x", gif->chcr._u32, gif->madr, gif->tadr);
mfifoGIFtransfer(mfifotransferred);
mfifotransferred = 0;
break;
}
default:
break;
}
case MFD_GIF:
{
if ((spr0->madr & ~dmacRegs->rbsr.RMSK) != dmacRegs->rbor.ADDR) Console.WriteLn("GIF MFIFO Write outside MFIFO area");
spr0->madr = dmacRegs->rbor.ADDR + (spr0->madr & dmacRegs->rbsr.RMSK);
//Console.WriteLn("mfifoGIFtransfer %x madr %x, tadr %x", gif->chcr._u32, gif->madr, gif->tadr);
mfifoGIFtransfer(mfifotransferred);
mfifotransferred = 0;
if (gif->chcr.STR) return;
break;
}
default:
break;
}
return;
}
if (!spr0finished) return;
spr0->chcr.STR = false;
@ -262,18 +258,23 @@ void dmaSPR0() // fromSPR
SPR_LOG("dmaSPR0 chcr = %lx, madr = %lx, qwc = %lx, sadr = %lx",
spr0->chcr._u32, spr0->madr, spr0->qwc, spr0->sadr);
if ((spr0->chcr.MOD == CHAIN_MODE) && spr0->qwc == 0)
spr0finished = false; //Init
if(spr0->chcr.MOD == CHAIN_MODE && spr0->qwc > 0)
{
tDMA_TAG *ptag;
ptag = (tDMA_TAG*)&psSu32(spr0->sadr); //Set memory pointer to SADR
CPU_INT(DMAC_FROM_SPR, /*ptag[0].QWC / BIAS*/ 4 );
return;
//DevCon.Warning(L"SPR0 QWC on Chain " + spr0->chcr.desc());
if(((spr0->chcr.TAG >> 12) & 0x7) == 0x7)
{
spr0finished = true;
}
else
{
spr0finished = false;
}
}
if(spr0->chcr.MOD == CHAIN_MODE && spr0->qwc > 0) DevCon.Warning(L"SPR0 QWC on Chain " + spr0->chcr.desc());
// COMPLETE HACK!!! For now at least.. FFX Videos dont rely on interrupts or reading DMA values
// It merely assumes that the last one has finished then starts another one (broke with the DMA fix)
// This "shouldn't" cause any problems as SPR is generally faster than the other DMAS anyway. (Refraction)
CPU_INT(DMAC_FROM_SPR, /*spr0->qwc / BIAS*/ 4 );
SPRFROMinterrupt();
}
__forceinline static void SPR1transfer(u32 *data, int size)
@ -295,12 +296,12 @@ int _SPR1chain()
SPR1transfer((u32*)pMem, spr1->qwc << 2);
spr1->madr += spr1->qwc << 4;
return (spr1->qwc) * BIAS;
return (spr1->qwc);
}
__forceinline void SPR1chain()
{
_SPR1chain();
CPU_INT(DMAC_TO_SPR, _SPR1chain() / BIAS);
spr1->qwc = 0;
}
@ -314,7 +315,7 @@ void _SPR1interleave()
if (tqwc == 0) tqwc = qwc;
SPR_LOG("SPR1 interleave size=%d, tqwc=%d, sqwc=%d, addr=%lx sadr=%lx",
spr1->qwc, tqwc, sqwc, spr1->madr, spr1->sadr);
CPU_INT(DMAC_TO_SPR, qwc / BIAS);
while (qwc > 0)
{
spr1->qwc = std::min(tqwc, qwc);
@ -348,9 +349,9 @@ void _dmaSPR1() // toSPR work function
if (spr1->qwc > 0)
{
SPR_LOG("spr1 Normal or in Progress size=%d, addr=%lx taddr=%lx saddr=%lx", spr1->qwc, spr1->madr, spr1->tadr, spr1->sadr);
// Transfer Dn_QWC from Dn_MADR to SPR1
SPR1chain();
spr1finished = true;
return;
}
// Chain Mode
@ -372,8 +373,8 @@ void _dmaSPR1() // toSPR work function
SPR1transfer((u32*)ptag, 4); //Transfer Tag
}
SPR_LOG("spr1 dmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx",
ptag[1]._u32, ptag[0]._u32, spr1->qwc, ptag->ID, spr1->madr);
SPR_LOG("spr1 dmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx taddr=%lx saddr=%lx",
ptag[1]._u32, ptag[0]._u32, spr1->qwc, ptag->ID, spr1->madr, spr1->tadr, spr1->sadr);
done = (hwDmacSrcChain(spr1, ptag->ID));
SPR1chain(); //Transfers the data set by the switch
@ -387,11 +388,6 @@ void _dmaSPR1() // toSPR work function
}
spr1finished = done;
if (!done)
{
ptag = SPRdmaGetAddr(spr1->tadr, false); //Set memory pointer to TADR
CPU_INT(DMAC_TO_SPR, /*(ptag[0].QWC / BIAS)*/ 4 );// the lower 16 bits of the tag / BIAS);
}
break;
}
//case INTERLEAVE_MODE:
@ -409,26 +405,35 @@ void dmaSPR1() // toSPR
" tadr = 0x%x, sadr = 0x%x",
spr1->chcr._u32, spr1->madr, spr1->qwc,
spr1->tadr, spr1->sadr);
if ((spr1->chcr.MOD == CHAIN_MODE) && (spr1->qwc == 0))
spr1finished = false; //Init
if(spr1->chcr.MOD == CHAIN_MODE && spr1->qwc > 0)
{
tDMA_TAG *ptag;
ptag = SPRdmaGetAddr(spr1->tadr, false); //Set memory pointer to TADR
CPU_INT(DMAC_TO_SPR, /*ptag[0].QWC / BIAS*/ 4 );
return;
//DevCon.Warning(L"SPR1 QWC on Chain " + spr1->chcr.desc());
if(((spr1->chcr.TAG >> 12) & 0x7) == 0x7 || ((spr1->chcr.TAG >> 12) & 0x7) == 0x0)
{
spr1finished = true;
}
else
{
spr1finished = false;
}
}
if(spr1->chcr.MOD == CHAIN_MODE && spr1->qwc > 0) DevCon.Warning(L"SPR1 QWC on Chain " + spr1->chcr.desc());
// COMPLETE HACK!!! For now at least.. FFX Videos dont rely on interrupts or reading DMA values
// It merely assumes that the last one has finished then starts another one (broke with the DMA fix)
// This "shouldn't" cause any problems as SPR is generally faster than the other DMAS anyway. (Refraction)
CPU_INT(DMAC_TO_SPR, /*spr1->qwc / BIAS*/ 4 );
SPRTOinterrupt();
}
void SPRTOinterrupt()
{
_dmaSPR1();
if (!spr1finished) return;
SPR_LOG("SPR1 Interrupt");
if (!spr1finished || spr1->qwc > 0)
{
_dmaSPR1();
return;
}
SPR_LOG("SPR1 End");
spr1->chcr.STR = false;
hwDmacIrq(DMAC_TO_SPR);
}

View File

@ -73,7 +73,7 @@ static __forceinline bool WriteIOPtoFifo()
hw_dma(9).madr += writeSize << 2;
// iop is 1/8th the clock rate of the EE and psxcycles is in words (not quadwords).
sif0.iop.cycles += (writeSize >> 2) * BIAS; // fixme : should be >> 4
sif0.iop.cycles += (writeSize >> 2)/* * BIAS*/; // fixme : should be >> 4
sif0.iop.counter -= writeSize;
return true;
@ -298,15 +298,21 @@ __forceinline void SIF0Dma()
if (sif0.iop.busy)
{
if(sif0.fifo.free() > 0) BusyCheck++;
HandleIOPTransfer();
if(sif0.fifo.free() > 0 || (sif0.iop.end == true && sif0.iop.counter == 0))
{
BusyCheck++;
HandleIOPTransfer();
}
}
if (sif0.ee.busy)
{
if(sif0.fifo.size >= 4) BusyCheck++;
HandleEETransfer();
if(sif0.fifo.size >= 4 || (sif0.ee.end == true && sif0dma->qwc == 0))
{
BusyCheck++;
HandleEETransfer();
}
}
} while (!done && BusyCheck > 0); // Substituting (sif0.ee.busy || sif0.iop.busy) breaks things.
} while (/*!done && */BusyCheck > 0); // Substituting (sif0.ee.busy || sif0.iop.busy) breaks things.
Sif0End();
}
@ -332,17 +338,17 @@ __forceinline void dmaSIF0()
SIF_LOG("warning, sif0.fifoReadPos != sif0.fifoWritePos");
}
if(sif0dma->chcr.MOD == CHAIN_MODE && sif0dma->qwc > 0) DevCon.Warning(L"SIF0 QWC on Chain CHCR " + sif0dma->chcr.desc());
//if(sif0dma->chcr.MOD == CHAIN_MODE && sif0dma->qwc > 0) DevCon.Warning(L"SIF0 QWC on Chain CHCR " + sif0dma->chcr.desc());
psHu32(SBUS_F240) |= 0x2000;
sif0.ee.busy = true;
if (sif0.iop.busy)
{
/*if (sif0.iop.busy)
{*/
XMMRegisters::Freeze();
hwIntcIrq(INTC_SBUS);
SIF0Dma();
psHu32(SBUS_F240) &= ~0x20;
psHu32(SBUS_F240) &= ~0x2000;
XMMRegisters::Thaw();
}
//}
}

View File

@ -176,7 +176,7 @@ static __forceinline void EndEE()
}
CPU_INT(DMAC_SIF1, min((int)(sif1.ee.cycles*BIAS), 384));
CPU_INT(DMAC_SIF1, /*min((int)(*/sif1.ee.cycles*BIAS/*), 384)*/);
}
// Stop processing IOP, and signal an interrupt.
@ -197,7 +197,7 @@ static __forceinline void EndIOP()
sif1.iop.cycles = 1;
}
// iop is 1/8th the clock rate of the EE and psxcycles is in words (not quadwords)
PSX_INT(IopEvt_SIF1, min((sif1.iop.cycles * 26), 1024));
PSX_INT(IopEvt_SIF1, /*min((*/sif1.iop.cycles/* * 26*//*), 1024)*/);
}
// Handle the EE transfer.
@ -292,17 +292,23 @@ __forceinline void SIF1Dma()
if (sif1.ee.busy)
{
if(sif1.fifo.free() > 0) BusyCheck++;
HandleEETransfer();
if(sif1.fifo.free() > 0 || (sif1.ee.end == true && sif1dma->qwc == 0))
{
BusyCheck++;
HandleEETransfer();
}
}
if (sif1.iop.busy)
{
if(sif1.fifo.size >= 4) BusyCheck++;
HandleIOPTransfer();
if(sif1.fifo.size >= 4 || (sif1.iop.end == true && sif1.iop.counter == 0))
{
BusyCheck++;
HandleIOPTransfer();
}
}
} while (!done && BusyCheck > 0);
} while (/*!done &&*/ BusyCheck > 0);
Sif1End();
}
@ -330,18 +336,18 @@ __forceinline void dmaSIF1()
SIF_LOG("warning, sif1.fifoReadPos != sif1.fifoWritePos");
}
if(sif1dma->chcr.MOD == CHAIN_MODE && sif1dma->qwc > 0) DevCon.Warning(L"SIF1 QWC on Chain CHCR " + sif1dma->chcr.desc());
//if(sif1dma->chcr.MOD == CHAIN_MODE && sif1dma->qwc > 0) DevCon.Warning(L"SIF1 QWC on Chain CHCR " + sif1dma->chcr.desc());
psHu32(SBUS_F240) |= 0x4000;
sif1.ee.busy = true;
if (sif1.iop.busy)
{
/*if (sif1.iop.busy)
{*/
XMMRegisters::Freeze();
SIF1Dma();
psHu32(SBUS_F240) &= ~0x40;
psHu32(SBUS_F240) &= ~0x100;
psHu32(SBUS_F240) &= ~0x4000;
XMMRegisters::Thaw();
}
//}
}

View File

@ -2057,7 +2057,7 @@ void _vuXGKICK(VURegs * VU)
u8* data = ((u8*)VU->Mem + ((VU->VI[_Is_].US[0]*16) & 0x3fff));
u32 size;
size = GetMTGS().PrepDataPacket( GIF_PATH_1, data, (0x4000-((VU->VI[_Is_].US[0]*16) & 0x3fff)) >> 4);
size = GetMTGS().PrepDataPacket( GIF_PATH_1, data, (0x4000-((VU->VI[_Is_].US[0]*16) & 0x3fff)) >> 4, false);
u8* pmem = GetMTGS().GetDataPacketPtr();
if((size << 4) > (u32)(0x4000-((VU->VI[_Is_].US[0]*16) & 0x3fff)))

View File

@ -23,7 +23,7 @@
vifStruct vif0;
vifStruct vif1;
tGSTransferStatus GSTransferStatus((STOPPED_MODE<<4) | (STOPPED_MODE<<2) | STOPPED_MODE);
tGSTransferStatus GSTransferStatus((STOPPED_MODE<<8) | (STOPPED_MODE<<4) | STOPPED_MODE);
void vif0Reset()
{
@ -140,8 +140,8 @@ _f void vif0FBRST(u32 value) {
g_vifCycles = 0;
// loop necessary for spiderman
vif0ch->chcr.STR = true;
CPU_INT(DMAC_VIF0, 0); // Gets the timing right - Flatout
//vif0ch->chcr.STR = true;
if(vif0ch->chcr.STR == true) CPU_INT(DMAC_VIF0, 0); // Gets the timing right - Flatout
}
}
}
@ -153,21 +153,28 @@ _f void vif1FBRST(u32 value) {
if (FBRST(value).RST) // Reset Vif.
{
memzero(vif1);
cpuRegs.interrupt &= ~((1 << 1) | (1 << 10)); //Stop all vif1 DMA's
vif1ch->qwc = 0; //?
//cpuRegs.interrupt &= ~((1 << 1) | (1 << 10)); //Stop all vif1 DMA's
vif1ch->qwc -= min((int)vif1ch->qwc, 16); //?
psHu64(VIF1_FIFO) = 0;
psHu64(VIF1_FIFO + 8) = 0;
vif1.done = false;
//vif1.done = false;
if(vif1Regs->mskpath3)
//DevCon.Warning("VIF FBRST Reset MSK = %x", vif1Regs->mskpath3);
if(vif1Regs->mskpath3 == 1 && GSTransferStatus.PTH3 == STOPPED_MODE && gif->chcr.STR == true)
{
vif1Regs->mskpath3 = 0;
gifRegs->stat.IMT = false;
if (gif->chcr.STR) CPU_INT(DMAC_GIF, 4);
//DevCon.Warning("VIF Path3 Resume on FBRST MSK = %x", vif1Regs->mskpath3);
gsInterrupt();
vif1Regs->mskpath3 = false;
gifRegs->stat.M3P = 0;
}
vif1Regs->mskpath3 = false;
gifRegs->stat.M3P = 0;
vif1Regs->err.reset();
vif1.inprogress = 0;
vif1.cmd = 0;
vif1.vifstalled = false;
vif1Regs->stat.FQC = 0;
vif1Regs->stat.clear_flags(VIF1_STAT_FDR | VIF1_STAT_INT | VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS | VIF1_STAT_VPS);
}
@ -217,18 +224,18 @@ _f void vif1FBRST(u32 value) {
{
case MFD_VIF1:
//Console.WriteLn("MFIFO Stall");
CPU_INT(10, 0);
if(vif1ch->chcr.STR == true) CPU_INT(10, 0);
break;
case NO_MFD:
case MFD_RESERVED:
case MFD_GIF: // Wonder if this should be with VIF?
// Gets the timing right - Flatout
CPU_INT(DMAC_VIF1, 0);
if(vif1ch->chcr.STR == true) CPU_INT(DMAC_VIF1, 0);
break;
}
vif1ch->chcr.STR = true;
//vif1ch->chcr.STR = true;
}
}
}

View File

@ -227,6 +227,7 @@ extern VIFregisters *vifRegs;
extern void dmaVIF0();
extern void dmaVIF1();
extern void mfifoVIF1transfer(int qwc);
extern bool VIF0transfer(u32 *data, int size, bool istag);
extern bool VIF1transfer(u32 *data, int size, bool istag);
extern bool VIF0transfer(u32 *data, int size);
extern bool VIF1transfer(u32 *data, int size);
extern void vifMFIFOInterrupt();
extern bool CheckPath2GIF(int channel);

View File

@ -23,10 +23,31 @@
// because its vif stalling not the EE core...
__forceinline void vif0FLUSH()
{
if(g_packetsizeonvu > vif0.vifpacketsize && g_vu0Cycles > 0)
{
//DevCon.Warning("Adding on same packet");
if( ((g_packetsizeonvu - vif0.vifpacketsize) >> 1) > g_vu0Cycles)
g_vu0Cycles -= (g_packetsizeonvu - vif0.vifpacketsize) >> 1;
else g_vu0Cycles = 0;
}
if(g_vu0Cycles > 0)
{
//DevCon.Warning("Adding %x cycles to VIF0", g_vu1Cycles * BIAS);
g_vifCycles += g_vu0Cycles;
g_vu0Cycles = 0;
}
g_vu0Cycles = 0;
if (!(VU0.VI[REG_VPU_STAT].UL & 1)) return;
if(VU0.flags & VUFLAG_MFLAGSET)
{
vif0.vifstalled = true;
return;
}
int _cycles = VU0.cycle;
vu0Finish();
//DevCon.Warning("VIF0 adding %x cycles", (VU0.cycle - _cycles) * BIAS);
g_vifCycles += (VU0.cycle - _cycles) * BIAS;
return;
}
bool _VIF0chain()
@ -52,9 +73,9 @@ bool _VIF0chain()
vif0ch->qwc, vif0ch->madr, vif0ch->tadr);
if (vif0.vifstalled)
return VIF0transfer(pMem + vif0.irqoffset, vif0ch->qwc * 4 - vif0.irqoffset, false);
return VIF0transfer(pMem + vif0.irqoffset, vif0ch->qwc * 4 - vif0.irqoffset);
else
return VIF0transfer(pMem, vif0ch->qwc * 4, false);
return VIF0transfer(pMem, vif0ch->qwc * 4);
}
__forceinline void vif0SetupTransfer()
@ -89,9 +110,9 @@ __forceinline void vif0SetupTransfer()
bool ret;
if (vif0.vifstalled)
ret = VIF0transfer((u32*)ptag + (2 + vif0.irqoffset), 2 - vif0.irqoffset, true); //Transfer Tag on stall
ret = VIF0transfer((u32*)ptag + (2 + vif0.irqoffset), 2 - vif0.irqoffset); //Transfer Tag on stall
else
ret = VIF0transfer((u32*)ptag + 2, 2, true); //Transfer Tag
ret = VIF0transfer((u32*)ptag + 2, 2); //Transfer Tag
if ((ret == false) && vif0.irqoffset < 2)
{
@ -124,6 +145,15 @@ __forceinline void vif0Interrupt()
if (!(vif0ch->chcr.STR)) Console.WriteLn("vif0 running when CHCR == %x", vif0ch->chcr._u32);
if (vif0.cmd)
{
if(vif0.done == true && vif0ch->qwc == 0) vif0Regs->stat.VPS = VPS_WAITING;
}
else
{
vif0Regs->stat.VPS = VPS_IDLE;
}
if (vif0.irq && vif0.tag.size == 0)
{
vif0Regs->stat.INT = true;
@ -134,25 +164,15 @@ __forceinline void vif0Interrupt()
vif0Regs->stat.FQC = 0;
// One game doesn't like vif stalling at end, can't remember what. Spiderman isn't keen on it tho
vif0ch->chcr.STR = false;
return;
}
else if ((vif0ch->qwc > 0) || (vif0.irqoffset > 0))
{
if (vif0.stallontag)
vif0SetupTransfer();
else
_VIF0chain();//CPU_INT(DMAC_STALL_SIS, vif0ch->qwc * BIAS);
//vif0ch->chcr.STR = false;
if(vif0ch->qwc > 0 || !vif0.done) return;
}
}
if (vif0.inprogress & 0x1)
{
_VIF0chain();
// VIF_NORMAL_FROM_MEM_MODE is a very slow operation.
// Timesplitters 2 depends on this beeing a bit higher than 128.
if (vif0.dmamode == VIF_NORMAL_FROM_MEM_MODE ) CPU_INT(DMAC_VIF0, 1024);
else CPU_INT(DMAC_VIF0, g_vifCycles);
CPU_INT(DMAC_VIF0, g_vifCycles);
return;
}
@ -182,7 +202,6 @@ __forceinline void vif0Interrupt()
if (vif0.cmd != 0) Console.WriteLn("vif0.cmd still set %x tag size %x", vif0.cmd, vif0.tag.size);
#endif
vif0Regs->stat.VPS = VPS_IDLE; //Vif goes idle as the stall happened between commands;
vif0ch->chcr.STR = false;
g_vifCycles = 0;
hwDmacIrq(DMAC_VIF0);
@ -197,24 +216,35 @@ void dmaVIF0()
vif0ch->tadr, vif0ch->asr0, vif0ch->asr1);
g_vifCycles = 0;
g_vu0Cycles = 0;
if(vif0.irqoffset != 0 && vif0.vifstalled == true) DevCon.Warning("Offset on VIF0 start!");
vif0.irqoffset = 0;
vif0.vifstalled = false;
vif0.inprogress = 0;
vif0.done = false;
if ((vif0ch->chcr.MOD == NORMAL_MODE) || vif0ch->qwc > 0) // Normal Mode
{
vif0.dmamode = VIF_NORMAL_TO_MEM_MODE;
if(vif0ch->chcr.MOD == CHAIN_MODE && vif0ch->qwc > 0) DevCon.Warning(L"VIF0 QWC on Chain CHCR " + vif0ch->chcr.desc());
if(vif0ch->chcr.MOD == CHAIN_MODE && vif0ch->qwc > 0)
{
vif0.dmamode = VIF_CHAIN_MODE;
//DevCon.Warning(L"VIF0 QWC on Chain CHCR " + vif0ch->chcr.desc());
vif0.inprogress |= 0x1;
if(((vif0ch->chcr.TAG >> 12) & 0x7) == 0x0 || ((vif0ch->chcr.TAG >> 12) & 0x7) == 0x7)
{
vif0.done = true;
}
}
}
else
{
vif0.dmamode = VIF_CHAIN_MODE;
}
if (vif0.dmamode != VIF_NORMAL_FROM_MEM_MODE)
vif0Regs->stat.FQC = 0x8;
else
vif0Regs->stat.FQC = min((u16)0x8, vif0ch->qwc);
vif0Regs->stat.FQC = min((u16)0x8, vif0ch->qwc);
// Chain Mode
vif0.done = false;
vif0Interrupt();
}

View File

@ -21,12 +21,38 @@
#include "VUmicro.h"
#include "newVif.h"
__forceinline void vif1FLUSH()
{
if (!(VU0.VI[REG_VPU_STAT].UL & 0x100)) return;
int _cycles = VU1.cycle;
vu1Finish();
g_vifCycles += (VU1.cycle - _cycles) * BIAS;
if(g_packetsizeonvu > vif1.vifpacketsize && g_vu1Cycles > 0)
{
//DevCon.Warning("Adding on same packet");
if( ((g_packetsizeonvu - vif1.vifpacketsize) >> 1) > g_vu1Cycles)
g_vu1Cycles -= (g_packetsizeonvu - vif1.vifpacketsize) >> 1;
else g_vu1Cycles = 0;
}
if(g_vu1Cycles > 0)
{
//DevCon.Warning("Adding %x cycles to VIF1", g_vu1Cycles * BIAS);
g_vifCycles += g_vu1Cycles;
g_vu1Cycles = 0;
}
g_vu1Cycles = 0;//else DevCon.Warning("VIF1 Different Packet, how can i work this out :/");
if (VU0.VI[REG_VPU_STAT].UL & 0x100)
{
int _cycles = VU1.cycle;
vu1Finish();
//DevCon.Warning("VIF1 adding %x cycles", (VU1.cycle - _cycles) * BIAS);
g_vifCycles += (VU1.cycle - _cycles) * BIAS;
}
if(gifRegs->stat.P1Q == true && (vif1.cmd & 0x7f) != 0x14 && (vif1.cmd & 0x7f) != 0x17)
{
vif1.vifstalled = true;
vif1Regs->stat.VGW = true;
vif1.GifWaitState = 2;
}
}
void vif1TransferToMemory()
@ -128,6 +154,7 @@ bool _VIF1chain()
if (vif1ch->qwc == 0)
{
vif1.inprogress = 0;
vif1.irqoffset = 0;
return true;
}
@ -152,9 +179,9 @@ bool _VIF1chain()
vif1ch->qwc, vif1ch->madr, vif1ch->tadr);
if (vif1.vifstalled)
return VIF1transfer(pMem + vif1.irqoffset, vif1ch->qwc * 4 - vif1.irqoffset, false);
return VIF1transfer(pMem + vif1.irqoffset, vif1ch->qwc * 4 - vif1.irqoffset);
else
return VIF1transfer(pMem, vif1ch->qwc * 4, false);
return VIF1transfer(pMem, vif1ch->qwc * 4);
}
__forceinline void vif1SetupTransfer()
@ -201,15 +228,16 @@ __forceinline void vif1SetupTransfer()
bool ret;
if (vif1.vifstalled)
ret = VIF1transfer((u32*)ptag + (2 + vif1.irqoffset), 2 - vif1.irqoffset, true); //Transfer Tag on stall
ret = VIF1transfer((u32*)ptag + (2 + vif1.irqoffset), 2 - vif1.irqoffset); //Transfer Tag on stall
else
ret = VIF1transfer((u32*)ptag + 2, 2, true); //Transfer Tag
ret = VIF1transfer((u32*)ptag + 2, 2); //Transfer Tag
if ((ret == false) && vif1.irqoffset < 2)
{
vif1.inprogress = 0; //Better clear this so it has to do it again (Jak 1)
return; //There has been an error or an interrupt
}
return; //IRQ set by VIFTransfer
} //else vif1.vifstalled = false;
}
vif1.irqoffset = 0;
@ -228,12 +256,92 @@ __forceinline void vif1SetupTransfer()
}
}
bool CheckPath2GIF(int channel)
{
if ((vif1Regs->stat.VGW))
{
if( vif1.GifWaitState == 0 ) //DIRECT/HL Check
{
if(GSTransferStatus.PTH3 < IDLE_MODE || gifRegs->stat.P1Q == true)
{
if(gifRegs->stat.IMT && GSTransferStatus.PTH3 <= IMAGE_MODE && (vif1.cmd & 0x7f) == 0x50 && gifRegs->stat.P1Q == false)
{
vif1Regs->stat.VGW = false;
}
else
{
//DevCon.Warning("VIF1-0 stall P1Q %x P2Q %x APATH %x PTH3 %x vif1cmd %x", gifRegs->stat.P1Q, gifRegs->stat.P2Q, gifRegs->stat.APATH, GSTransferStatus.PTH3, vif1.cmd);
CPU_INT(channel, 8);
return false;
}
}
else
{
vif1Regs->stat.VGW = false;
}
}
else if( vif1.GifWaitState == 1 ) // Else we're flushing path3 :), but of course waiting for the microprogram to finish
{
if(gifRegs->stat.P1Q == true)
{
//DevCon.Warning("VIF1-1 stall P1Q %x P2Q %x APATH %x PTH3 %x vif1cmd %x", gifRegs->stat.P1Q, gifRegs->stat.P2Q, gifRegs->stat.APATH, GSTransferStatus.PTH3, vif1.cmd);
CPU_INT(channel, 8);
return false;
}
if (GSTransferStatus.PTH3 < PENDINGSTOP_MODE)
{
//DevCon.Warning("VIF1-11 stall P1Q %x P2Q %x APATH %x PTH3 %x vif1cmd %x", gifRegs->stat.P1Q, gifRegs->stat.P2Q, gifRegs->stat.APATH, GSTransferStatus.PTH3, vif1.cmd);
//DevCon.Warning("PTH3 %x P1Q %x P3Q %x IP3 %x", GSTransferStatus.PTH3, gifRegs->stat.P1Q, gifRegs->stat.P3Q, gifRegs->stat.IP3 );
CPU_INT(channel, 8);
return false;
}
else
{
vif1Regs->stat.VGW = false;
}
}
else if( vif1.GifWaitState == 3 ) // Else we're flushing path3 :), but of course waiting for the microprogram to finish
{
if (gifRegs->ctrl.PSE)
{
//DevCon.Warning("VIF1-1 stall P1Q %x P2Q %x APATH %x PTH3 %x vif1cmd %x", gifRegs->stat.P1Q, gifRegs->stat.P2Q, gifRegs->stat.APATH, GSTransferStatus.PTH3, vif1.cmd);
CPU_INT(channel, 8);
return false;
}
else
{
vif1Regs->stat.VGW = false;
}
}
else //Normal Flush
{
if(gifRegs->stat.P1Q == true)
{
//DevCon.Warning("VIF1-2 stall P1Q %x P2Q %x APATH %x PTH3 %x vif1cmd %x", gifRegs->stat.P1Q, gifRegs->stat.P2Q, gifRegs->stat.APATH, GSTransferStatus.PTH3, vif1.cmd);
CPU_INT(channel, 8);
return false;
}
else
{
vif1Regs->stat.VGW = false;
}
}
}
return true;
}
__forceinline void vif1Interrupt()
{
VIF_LOG("vif1Interrupt: %8.8x", cpuRegs.cycle);
g_vifCycles = 0;
if (schedulepath3msk & 0x10)
{
Vif1MskPath3();
CPU_INT(DMAC_VIF1, 8);
return;
}
//Some games (Fahrenheit being one) start vif first, let it loop through blankness while it sets MFIFO mode, so we need to check it here.
if (dmacRegs->ctrl.MFD == MFD_VIF1) // VIF MFIFO
{
@ -245,31 +353,31 @@ __forceinline void vif1Interrupt()
return;
}
if(vif1ch->chcr.DIR && CheckPath2GIF(DMAC_VIF1) == false) return;
//We need to check the direction, if it is downloading from the GS, we handle that seperately (KH2 for testing)
if (vif1ch->chcr.DIR)vif1Regs->stat.FQC = min(vif1ch->qwc, (u16)16);
//Simulated GS transfer time done, clear the flags
if(gifRegs->stat.APATH == GIF_APATH2 && (vif1.cmd & 0x70) != 0x50)
if(GSTransferStatus.PTH2 == PENDINGSTOP_MODE)
{
gifRegs->stat.APATH = GIF_APATH_IDLE;
GSTransferStatus.PTH2 = STOPPED_MODE;
/*gifRegs->stat.APATH = GIF_APATH_IDLE;
if(gifRegs->stat.DIR == 0)gifRegs->stat.OPH = false;*/
}
if (schedulepath3msk & 0x10) Vif1MskPath3();
if ((vif1Regs->stat.VGW))
{
if (GSTransferStatus.PTH3 < STOPPED_MODE || GSTransferStatus.PTH1 != STOPPED_MODE)
{
CPU_INT(DMAC_VIF1, 4);
return;
}
else
{
vif1Regs->stat.VGW = false;
}
}
if (!(vif1ch->chcr.STR)) Console.WriteLn("Vif1 running when CHCR == %x", vif1ch->chcr._u32);
if (vif1.cmd)
{
if(vif1.done == true && vif1ch->qwc == 0) vif1Regs->stat.VPS = VPS_WAITING;
}
else
{
vif1Regs->stat.VPS = VPS_IDLE;
}
if (vif1.irq && vif1.tag.size == 0)
{
vif1Regs->stat.INT = true;
@ -279,16 +387,9 @@ __forceinline void vif1Interrupt()
{
//vif1Regs->stat.FQC = 0;
// One game doesn't like vif stalling at end, can't remember what. Spiderman isn't keen on it tho
vif1ch->chcr.STR = false;
return;
}
else if ((vif1ch->qwc > 0) || (vif1.irqoffset > 0))
{
if (vif1.stallontag)
vif1SetupTransfer();
else
_VIF1chain();//CPU_INT(DMAC_STALL_SIS, vif1ch->qwc * BIAS);
//NFSHPS stalls when the whole packet has gone across (it stalls int he last 32bit cmd)
//In this case VIF will end
if(vif1ch->qwc > 0 || !vif1.done) return;
}
}
@ -330,13 +431,15 @@ __forceinline void vif1Interrupt()
if (vif1.cmd != 0) Console.WriteLn("vif1.cmd still set %x tag size %x", vif1.cmd, vif1.tag.size);
#endif
vif1Regs->stat.VPS = VPS_IDLE; //Vif goes idle as the stall happened between commands;
if((vif1ch->chcr.DIR == VIF_NORMAL_TO_MEM_MODE) && vif1.GSLastDownloadSize <= 16)
{ //Reverse fifo has finished and nothing is left, so lets clear the outputting flag
gifRegs->stat.OPH = false;
}
vif1ch->chcr.STR = false;
vif1.vifstalled = false;
g_vifCycles = 0;
g_vu1Cycles = 0;
VIF_LOG("VIF1 End");
hwDmacIrq(DMAC_VIF1);
@ -350,7 +453,12 @@ void dmaVIF1()
vif1ch->tadr, vif1ch->asr0, vif1ch->asr1);
vif1.done = false;
if(vif1.irqoffset != 0 && vif1.vifstalled == true) DevCon.Warning("Offset on VIF1 start!");
vif1.irqoffset = 0;
vif1.vifstalled = false;
g_vifCycles = 0;
g_vu1Cycles = 0;
vif1.inprogress = 0;
#ifdef PCSX2_DEVBUILD
@ -371,7 +479,16 @@ void dmaVIF1()
else
vif1.dmamode = VIF_NORMAL_TO_MEM_MODE;
if(vif1ch->chcr.MOD == CHAIN_MODE && vif1ch->qwc > 0) DevCon.Warning(L"VIF1 QWC on Chain CHCR " + vif1ch->chcr.desc());
if(vif1ch->chcr.MOD == CHAIN_MODE && vif1ch->qwc > 0)
{
vif1.dmamode = VIF_CHAIN_MODE;
//DevCon.Warning(L"VIF1 QWC on Chain CHCR " + vif1ch->chcr.desc());
vif1.inprogress |= 0x1;
if(((vif1ch->chcr.TAG >> 12) & 0x7) == 0x0 || ((vif1ch->chcr.TAG >> 12) & 0x7) == 0x7)
{
vif1.done = true;
}
}
}
else
{

View File

@ -22,11 +22,19 @@
VIFregisters *vifRegs;
vifStruct *vif;
u16 vifqwc = 0;
int g_vifCycles = 0;
u32 g_vifCycles = 0;
u32 g_vu0Cycles = 0;
u32 g_vu1Cycles = 0;
u32 g_packetsizeonvu = 0;
__aligned16 VifMaskTypes g_vifmask;
extern int g_vifCycles;
extern u32 g_vifCycles;
static u32 qwctag(u32 mask)
{
return (dmacRegs->rbor.ADDR + (mask & dmacRegs->rbsr.RMSK));
}
static __forceinline bool mfifoVIF1rbTransfer()
{
@ -48,10 +56,12 @@ static __forceinline bool mfifoVIF1rbTransfer()
if (src == NULL) return false;
if (vif1.vifstalled)
ret = VIF1transfer(src + vif1.irqoffset, s1 - vif1.irqoffset, false);
ret = VIF1transfer(src + vif1.irqoffset, s1 - vif1.irqoffset);
else
ret = VIF1transfer(src, s1, false);
ret = VIF1transfer(src, s1);
vif1ch->madr = qwctag(vif1ch->madr);
if (ret)
{
/* and second copy 's2' bytes from 'maddr' to '&data[s1]' */
@ -59,8 +69,10 @@ static __forceinline bool mfifoVIF1rbTransfer()
src = (u32*)PSM(maddr);
if (src == NULL) return false;
VIF1transfer(src, ((mfifoqwc << 2) - s1), false);
VIF1transfer(src, ((mfifoqwc << 2) - s1));
}
vif1ch->madr = qwctag(vif1ch->madr);
}
else
{
@ -71,9 +83,12 @@ static __forceinline bool mfifoVIF1rbTransfer()
if (src == NULL) return false;
if (vif1.vifstalled)
ret = VIF1transfer(src + vif1.irqoffset, mfifoqwc * 4 - vif1.irqoffset, false);
ret = VIF1transfer(src + vif1.irqoffset, mfifoqwc * 4 - vif1.irqoffset);
else
ret = VIF1transfer(src, mfifoqwc << 2, false);
ret = VIF1transfer(src, mfifoqwc << 2);
vif1ch->madr = qwctag(vif1ch->madr);
}
return ret;
}
@ -83,7 +98,7 @@ static __forceinline bool mfifo_VIF1chain()
bool ret;
/* Is QWC = 0? if so there is nothing to transfer */
if ((vif1ch->qwc == 0) && (!vif1.vifstalled))
if ((vif1ch->qwc == 0))
{
vif1.inprogress &= ~1;
return true;
@ -95,6 +110,7 @@ static __forceinline bool mfifo_VIF1chain()
u16 startqwc = vif1ch->qwc;
ret = mfifoVIF1rbTransfer();
vifqwc -= startqwc - vif1ch->qwc;
}
else
{
@ -104,17 +120,14 @@ static __forceinline bool mfifo_VIF1chain()
if (pMem == NULL) return false;
if (vif1.vifstalled)
ret = VIF1transfer((u32*)pMem + vif1.irqoffset, vif1ch->qwc * 4 - vif1.irqoffset, false);
ret = VIF1transfer((u32*)pMem + vif1.irqoffset, vif1ch->qwc * 4 - vif1.irqoffset);
else
ret = VIF1transfer((u32*)pMem, vif1ch->qwc << 2, false);
ret = VIF1transfer((u32*)pMem, vif1ch->qwc << 2);
}
return ret;
}
static u32 qwctag(u32 mask)
{
return (dmacRegs->rbor.ADDR + (mask & dmacRegs->rbsr.RMSK));
}
void mfifoVIF1transfer(int qwc)
{
@ -148,19 +161,20 @@ void mfifoVIF1transfer(int qwc)
{
bool ret;
if (vif1.stallontag)
ret = VIF1transfer((u32*)ptag + (2 + vif1.irqoffset), 2 - vif1.irqoffset, true); //Transfer Tag on Stall
if (vif1.vifstalled)
ret = VIF1transfer((u32*)ptag + (2 + vif1.irqoffset), 2 - vif1.irqoffset); //Transfer Tag on Stall
else
ret = VIF1transfer((u32*)ptag + 2, 2, true); //Transfer Tag
ret = VIF1transfer((u32*)ptag + 2, 2); //Transfer Tag
if (!(ret))
if ((ret == false) && vif1.irqoffset < 2)
{
VIF_LOG("MFIFO Stall on tag");
vif1.stallontag = true;
return; //IRQ set by VIFTransfer
}
} //else vif1.vifstalled = false;
}
vif1.irqoffset = 0;
vif1ch->unsafeTransfer(ptag);
vif1ch->madr = ptag[1]._u32;
@ -224,29 +238,25 @@ void vifMFIFOInterrupt()
if (schedulepath3msk & 0x10) Vif1MskPath3();
if(gifRegs->stat.APATH == GIF_APATH2 && (vif1.cmd & 0x70) != 0x50)
if(vif1ch->chcr.DIR && CheckPath2GIF(10) == false) return;
//We need to check the direction, if it is downloading from the GS, we handle that seperately (KH2 for testing)
//Simulated GS transfer time done, clear the flags
if(GSTransferStatus.PTH2 == PENDINGSTOP_MODE)
{
gifRegs->stat.APATH = GIF_APATH_IDLE;
GSTransferStatus.PTH2 = STOPPED_MODE;
/*gifRegs->stat.APATH = GIF_APATH_IDLE;
if(gifRegs->stat.DIR == 0)gifRegs->stat.OPH = false;*/
}
if ((vif1Regs->stat.VGW))
if (vif1.cmd)
{
if (GSTransferStatus.PTH3 < STOPPED_MODE || GSTransferStatus.PTH1 != STOPPED_MODE)
{
CPU_INT(10, 4);
return;
}
else
{
vif1Regs->stat.VGW = false;
}
if(vif1.done == true && vif1ch->qwc == 0) vif1Regs->stat.VPS = VPS_WAITING;
}
if ((spr0->chcr.STR) && (spr0->qwc == 0))
else
{
spr0->chcr.STR = false;
hwDmacIrq(DMAC_FROM_SPR);
vif1Regs->stat.VPS = VPS_IDLE;
}
if (vif1.irq && vif1.tag.size == 0)
@ -257,9 +267,9 @@ void vifMFIFOInterrupt()
if (vif1Regs->stat.test(VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS))
{
vif1Regs->stat.FQC = 0; // FQC=0
vif1ch->chcr.STR = false;
return;
/*vif1Regs->stat.FQC = 0; // FQC=0
vif1ch->chcr.STR = false;*/
if(vif1ch->qwc > 0 || !vif1.done) return;
}
}
@ -302,6 +312,7 @@ void vifMFIFOInterrupt()
hwDmacIrq(DMAC_MFIFO_EMPTY);
}*/
vif1.vifstalled = false;
vif1.done = 1;
g_vifCycles = 0;
vif1ch->chcr.STR = false;

View File

@ -39,7 +39,10 @@ static _f void vifFlush(int idx) {
static _f void vuExecMicro(int idx, u32 addr) {
VURegs* VU = nVif[idx].VU;
vifFlush(idx);
int startcycles = 0;
//vifFlush(idx);
//if(vifX.vifstalled == true) return;
if (VU->vifRegs->itops > (idx ? 0x3ffu : 0xffu)) {
Console.WriteLn("VIF%d ITOP overrun! %x", idx, VU->vifRegs->itops);
@ -65,8 +68,16 @@ static _f void vuExecMicro(int idx, u32 addr) {
}
}
if(!idx)startcycles = VU0.cycle;
else startcycles = VU1.cycle;
if (!idx) vu0ExecMicro(addr);
else vu1ExecMicro(addr);
if(!idx) { g_vu0Cycles += (VU0.cycle-startcycles) * BIAS; g_packetsizeonvu = vif0.vifpacketsize; }
else { g_vu1Cycles += (VU1.cycle-startcycles) * BIAS; g_packetsizeonvu = vif1.vifpacketsize; }
//DevCon.Warning("Ran VU%x, VU0 Cycles %x, VU1 Cycles %x", idx, g_vu0Cycles, g_vu1Cycles);
vifX.vifstalled = true;
}
u8 schedulepath3msk = 0;
@ -74,17 +85,20 @@ u8 schedulepath3msk = 0;
void Vif1MskPath3() {
vif1Regs->mskpath3 = schedulepath3msk & 0x1;
//Console.WriteLn("VIF MSKPATH3 %x", vif1Regs->mskpath3);
//Console.WriteLn("VIF MSKPATH3 %x gif str %x path3 status %x", vif1Regs->mskpath3, gif->chcr.STR, GSTransferStatus.PTH3);
gifRegs->stat.M3P = vif1Regs->mskpath3;
if (!vif1Regs->mskpath3) {
//Let the Gif know it can transfer again (making sure any vif stall isnt unset prematurely)
if(gif->chcr.STR == true)
{
GSTransferStatus.PTH3 = 3;
CPU_INT(DMAC_GIF, 4);
}
}
if (!vif1Regs->mskpath3)
{
//if(GSTransferStatus.PTH3 > TRANSFER_MODE && gif->chcr.STR) GSTransferStatus.PTH3 = TRANSFER_MODE;
//DevCon.Warning("Mask off");
if(GSTransferStatus.PTH3 >= PENDINGSTOP_MODE) GSTransferStatus.PTH3 = IDLE_MODE;
if(gifRegs->stat.P3Q)
{
gsInterrupt();//gsInterrupt();
}
} else if(!gif->chcr.STR && GSTransferStatus.PTH3 == IDLE_MODE) GSTransferStatus.PTH3 = STOPPED_MODE;//else DevCon.Warning("Mask on");
schedulepath3msk = 0;
}
@ -105,24 +119,46 @@ template<int idx> _f int _vifCode_Direct(int pass, u8* data, bool isDirectHL) {
vif1Only();
int vifImm = (u16)vif1Regs->code;
vif1.tag.size = vifImm ? (vifImm*4) : (65536*4);
return 1;
vif1.vifstalled = true;
gifRegs->stat.P2Q = true;
if (gifRegs->stat.PSE) // temporarily stop
{
Console.WriteLn("Gif dma temp paused? VIF DIRECT");
vif1.GifWaitState = 3;
vif1Regs->stat.VGW = true;
}
//Should cause this to split here to try and time PATH3 right.
return 0;
}
pass2 {
vif1Only();
//return vifTrans_DirectHL<idx>((u32*)data);
gifRegs->stat.P2Q = true;
//Should probably do this for both types of transfer seen as the GS hates taking 2 seperate chunks
//if (isDirectHL) {
if (GSTransferStatus.PTH3 < STOPPED_MODE || GSTransferStatus.PTH1 != STOPPED_MODE)
if (GSTransferStatus.PTH3 < IDLE_MODE || gifRegs->stat.P1Q == true)
{
/*if(!isDirectHL) DevCon.WriteLn("Direct: Waiting for Path3 to finish!");
else DevCon.WriteLn("DirectHL: Waiting for Path3 to finish!");*/
//VIF_LOG("Mask %x, GIF STR %x, PTH1 %x, PTH2 %x, PTH3 %x", vif1Regs->mskpath3, gif->chcr.STR, GSTransferStatus.PTH1, GSTransferStatus.PTH2, GSTransferStatus.PTH3);
vif1Regs->stat.VGW = true; // PATH3 is in image mode, so wait for end of transfer
vif1.vifstalled = true;
if(gifRegs->stat.APATH == GIF_APATH2 || ((GSTransferStatus.PTH3 <= IMAGE_MODE && gifRegs->stat.IMT && (vif1.cmd & 0x7f) == 0x50)) && gifRegs->stat.P1Q == false)
{
//Do nothing, allow it
vif1Regs->stat.VGW = false;
//if(gifRegs->stat.APATH != GIF_APATH2)DevCon.Warning("Continue DIRECT/HL %x P3 %x APATH %x P1Q %x", vif1.cmd, GSTransferStatus.PTH3, gifRegs->stat.APATH, gifRegs->stat.P1Q);
}
else
{
//DevCon.Warning("Stall DIRECT/HL %x P3 %x APATH %x P1Q %x", vif1.cmd, GSTransferStatus.PTH3, gifRegs->stat.APATH, gifRegs->stat.P1Q);
vif1Regs->stat.VGW = true; // PATH3 is in image mode (DIRECTHL), or busy (BOTH no IMT)
vif1.GifWaitState = 0;
vif1.vifstalled = true;
return 0;
}
}
if (gifRegs->stat.PSE) // temporarily stop
{
Console.WriteLn("Gif dma temp paused? VIF DIRECT");
vif1.GifWaitState = 3;
vif1Regs->stat.VGW = true;
return 0;
}
//}
gifRegs->stat.clear_flags(GIF_STAT_P2Q);
Registers::Freeze();
@ -131,31 +167,72 @@ template<int idx> _f int _vifCode_Direct(int pass, u8* data, bool isDirectHL) {
u32 size = ret << 2;
gifRegs->stat.APATH = GIF_APATH2; //Flag is cleared in vif1interrupt to simulate it being in progress.
if (ret == v.vif->tag.size) { // Full Transfer
if (v.bSize) { // Last transfer was partial
memcpy_fast(&v.buffer[v.bSize], data, size);
v.bSize += size;
data = v.buffer;
size = v.bSize;
}
//In the original code we were saving this data, it seems if it does happen, its just blank, so we ignore it.
if (!size) { DevCon.WriteLn("Path2: No Data Transfer?"); }
const uint count = GetMTGS().PrepDataPacket(GIF_PATH_2, data, size >> 4);
memcpy_fast(GetMTGS().GetDataPacketPtr(), data, count << 4);
GetMTGS().SendDataPacket();
vif1.tag.size = 0;
vif1.cmd = 0;
v.bSize = 0;
}
else { // Partial Transfer
//DevCon.WriteLn("DirectHL: Partial Transfer [%d]", size);
memcpy_fast(&v.buffer[v.bSize], data, size);
v.bSize += size;
vif1.tag.size -= ret;
}
Registers::Thaw();
return ret;
if(vif1.vifpacketsize < 4 && v.bSize < 16)
{
nVifStruct& v = nVif[idx];
memcpy(&v.buffer[v.bPtr], data, vif1.vifpacketsize << 2);
v.bSize += vif1.vifpacketsize << 2;
v.bPtr += vif1.vifpacketsize << 2;
vif1.tag.size -= vif1.vifpacketsize;
Registers::Thaw();
if(vif1.tag.size == 0)
{
DevCon.Warning("Missaligned packet on DIRECT end!");
vif1.cmd = 0;
}
return vif1.vifpacketsize;
}
else
{
nVifStruct& v = nVif[idx];
if(v.bSize)
{
int ret = 0;
if(v.bSize < 16)
{
if(((16 - v.bSize) >> 2) > vif1.vifpacketsize) DevCon.Warning("Not Enough Data!");
ret = (16 - v.bSize) >> 2;
memcpy(&v.buffer[v.bPtr], data, ret << 2);
vif1.tag.size -= ret;
v.bSize = 0;
v.bPtr = 0;
}
const uint count = GetMTGS().PrepDataPacket(GIF_PATH_2, v.buffer, 1, false);
memcpy_fast(GetMTGS().GetDataPacketPtr(), v.buffer, count << 4);
GetMTGS().SendDataPacket();
if(vif1.tag.size == 0)
{
vif1.cmd = 0;
}
vif1.vifstalled = true;
Registers::Thaw();
return ret;
}
else
{
const uint count = GetMTGS().PrepDataPacket(GIF_PATH_2, data, size >> 4, false);
memcpy_fast(GetMTGS().GetDataPacketPtr(), data, count << 4);
GetMTGS().SendDataPacket();
vif1.tag.size -= count << 2;
if(vif1.tag.size == 0)
{
vif1.cmd = 0;
}
vif1.vifstalled = true;
Registers::Thaw();
return count << 2;
}
}
}
return 0;
}
@ -173,7 +250,7 @@ vifOp(vifCode_DirectHL) {
// ToDo: FixMe
vifOp(vifCode_Flush) {
vif1Only();
pass1 { vifFlush(idx); vifX.cmd = 0; }
pass1 { vifFlush(idx); vifX.cmd = 0; }
pass3 { DevCon.WriteLn("vifCode_Flush"); }
return 0;
}
@ -182,16 +259,22 @@ vifOp(vifCode_Flush) {
vifOp(vifCode_FlushA) {
vif1Only();
pass1 {
vifFlush(idx);
// Gif is already transferring so wait for it.
if (GSTransferStatus.PTH3 < STOPPED_MODE) {
if (gifRegs->stat.P1Q == true || GSTransferStatus.PTH3 < PENDINGSTOP_MODE) {
//DevCon.Warning("VIF FlushA Wait MSK = %x", vif1Regs->mskpath3);
//
//DevCon.WriteLn("FlushA path3 Wait! PTH3 MD %x STR %x", GSTransferStatus.PTH3, gif->chcr.STR);
vif1Regs->stat.VGW = true;
vif1.GifWaitState = 1;
vifX.vifstalled = true;
}
vifFlush(idx);
vifX.cmd = 0;
} // else DevCon.WriteLn("FlushA path3 no Wait! PTH3 MD %x STR %x", GSTransferStatus.PTH3, gif->chcr.STR);
}
pass3 { DevCon.WriteLn("vifCode_FlushA"); }
vifX.cmd = 0;
return 0;
}
@ -234,10 +317,10 @@ vifOp(vifCode_MPG) {
int vifNum = (u8)(vifXRegs->code >> 16);
vifX.tag.addr = (u16)(vifXRegs->code << 3) & (idx ? 0x3fff : 0xfff);
vifX.tag.size = vifNum ? (vifNum*2) : 512;
//vifFlush(idx);
return 1;
}
pass2 {
vifFlush(idx);
if (vifX.vifpacketsize < vifX.tag.size) { // Partial Transfer
if((vifX.tag.addr + vifX.vifpacketsize) > (idx ? 0x4000 : 0x1000)) {
DevCon.Warning("Vif%d MPG Split Overflow", idx);
@ -263,19 +346,19 @@ vifOp(vifCode_MPG) {
}
vifOp(vifCode_MSCAL) {
pass1 { vuExecMicro(idx, (u16)(vifXRegs->code) << 3); vifX.cmd = 0; }
pass1 { vifFlush(idx); vuExecMicro(idx, (u16)(vifXRegs->code) << 3); vifX.cmd = 0;}
pass3 { DevCon.WriteLn("vifCode_MSCAL"); }
return 0;
}
vifOp(vifCode_MSCALF) {
pass1 { vuExecMicro(idx, (u16)(vifXRegs->code) << 3); vifX.cmd = 0; }
pass1 { vifFlush(idx); vuExecMicro(idx, (u16)(vifXRegs->code) << 3); vifX.cmd = 0; }
pass3 { DevCon.WriteLn("vifCode_MSCALF"); }
return 0;
}
vifOp(vifCode_MSCNT) {
pass1 { vuExecMicro(idx, -1); vifX.cmd = 0; }
pass1 { vifFlush(idx); vuExecMicro(idx, -1); vifX.cmd = 0; }
pass3 { DevCon.WriteLn("vifCode_MSCNT"); }
return 0;
}
@ -284,7 +367,7 @@ vifOp(vifCode_MSCNT) {
vifOp(vifCode_MskPath3) {
vif1Only();
pass1 {
if (vif1ch->chcr.STR) {
if (vif1ch->chcr.STR && vifX.lastcmd != 0x13) {
schedulepath3msk = 0x10 | ((vif1Regs->code >> 15) & 0x1);
vif1.vifstalled = true;
}

View File

@ -75,7 +75,9 @@ struct vifStruct {
u32 savedtag; // need this for backwards compat with save states
u32 vifpacketsize;
u8 inprogress;
u32 lastcmd;
u8 dmamode;
u8 GifWaitState; // 0 = General PATH checking, 1 = Flush path 3, 2 == Wait for VU1
};
extern vifStruct* vif;
@ -110,8 +112,10 @@ enum VifModes
static const unsigned int VIF0intc = 4;
static const unsigned int VIF1intc = 5;
extern int g_vifCycles;
extern u32 g_vifCycles;
extern u32 g_vu0Cycles;
extern u32 g_vu1Cycles;
extern u32 g_packetsizeonvu;
extern void vif0FLUSH();
extern void vif1FLUSH();

View File

@ -69,6 +69,7 @@ _vifT void vifTransferLoop(u32* &data) {
while (pSize > 0 && !vifX.vifstalled) {
if(!vifX.cmd) { // Get new VifCode
vifX.lastcmd = (vifXRegs->code >> 24) & 0x7f;
vifXRegs->code = data[0];
vifX.cmd = data[0] >> 24;
iBit = data[0] >> 31;
@ -84,8 +85,7 @@ _vifT void vifTransferLoop(u32* &data) {
pSize -= ret;
if (analyzeIbit<idx>(data, iBit)) break;
}
if (vifX.cmd) vifXRegs->stat.VPS = VPS_WAITING;
else vifXRegs->stat.VPS = VPS_IDLE;
if (pSize) vifX.vifstalled = true;
}
@ -97,14 +97,30 @@ _vifT _f bool vifTransfer(u32 *data, int size) {
vifX.vifstalled = false;
vifX.stallontag = false;
vifX.vifpacketsize = size;
g_packetsizeonvu = size;
vifTransferLoop<idx>(data);
transferred += size - vifX.vifpacketsize;
g_vifCycles +=(transferred >> 2) * BIAS; /* guessing */
g_vifCycles +=((transferred * BIAS) >> 2) ; /* guessing */
if(!idx && g_vu0Cycles > 0)
{
if(g_vifCycles < g_vu0Cycles) g_vu0Cycles -= g_vifCycles;
else if(g_vifCycles >= g_vu0Cycles)g_vu0Cycles = 0;
}
else if(idx && g_vu1Cycles > 0)
{
if(g_vifCycles < g_vu1Cycles) g_vu1Cycles -= g_vifCycles;
else if(g_vifCycles >= g_vu1Cycles)g_vu1Cycles = 0;
}
vifX.irqoffset = transferred % 4; // cannot lose the offset
transferred = transferred >> 2;
vifXch->madr +=(transferred << 4);
vifXch->qwc -= transferred;
@ -125,9 +141,9 @@ _vifT _f bool vifTransfer(u32 *data, int size) {
return !vifX.vifstalled;
}
bool VIF0transfer(u32 *data, int size, bool istag) {
bool VIF0transfer(u32 *data, int size) {
return vifTransfer<0>(data, size);
}
bool VIF1transfer(u32 *data, int size, bool istag) {
bool VIF1transfer(u32 *data, int size) {
return vifTransfer<1>(data, size);
}

View File

@ -306,7 +306,8 @@ _vifT void vifUnpackSetup(u32 *data) {
return; // Skipping write and 0 write-cycles, so do nothing!
}
if (!idx) vif0FLUSH(); // Only VU0?
//if (!idx) vif0FLUSH(); // Only VU0?
vifX.usn = (vifXRegs->code >> 14) & 0x01;
int vifNum = (vifXRegs->code >> 16) & 0xff;
@ -330,6 +331,8 @@ _vifT void vifUnpackSetup(u32 *data) {
if (idx && ((addr>>15)&1)) addr += vif1Regs->tops;
vifX.tag.addr = (addr<<4) & (idx ? 0x3ff0 : 0xff0);
VIF_LOG("Unpack VIF%x, QWC %x tagsize %x", idx, vifNum, vif0.tag.size);
vifX.cl = 0;
vifX.tag.cmd = vifX.cmd;
vifXRegs->offset = 0;

View File

@ -100,7 +100,7 @@ struct GIFPath
bool StepReg();
u8 GetReg();
int ParseTag(GIF_PATH pathidx, const u8* pMem, u32 size);
int ParseTag(GIF_PATH pathidx, const u8* pMem, u32 size, bool TestOnly);
};
typedef void (__fastcall *GIFRegHandler)(const u32* data);
@ -280,9 +280,13 @@ static __forceinline void gsHandler(const u8* pMem)
const int reg = pMem[8];
if (reg == 0x50)
{
vif1.BITBLTBUF._u64 = *(u64*)pMem;
}
else if (reg == 0x52)
{
vif1.TRXREG._u64 = *(u64*)pMem;
}
else if (reg == 0x53)
{
// local -> host
@ -316,7 +320,6 @@ static __forceinline void gsHandler(const u8* pMem)
// qwords, rounded down; any extra bits are lost
// games must take care to ensure transfer rectangles are exact multiples of a qword
vif1.GSLastDownloadSize = vif1.TRXREG.RRW * vif1.TRXREG.RRH * bpp >> 7;
VIF_LOG("GS Download size %x", vif1.GSLastDownloadSize);
gifRegs->stat.OPH = true;
}
}
@ -341,10 +344,9 @@ static __forceinline void gsHandler(const u8* pMem)
// Parameters:
// size (path1) - difference between the end of VU memory and pMem.
// size (path2/3) - max size of incoming data stream, in qwc (simd128)
__forceinline int GIFPath::ParseTag(GIF_PATH pathidx, const u8* pMem, u32 size)
__forceinline int GIFPath::ParseTag(GIF_PATH pathidx, const u8* pMem, u32 size, bool TestOnly)
{
const u8* vuMemEnd = pMem + (size<<4); // End of VU1 Mem
if (pathidx==GIF_PATH_1) size = 0x400; // VU1 mem size
u32 startSize = size; // Start Size
while (size > 0) {
@ -352,27 +354,36 @@ __forceinline int GIFPath::ParseTag(GIF_PATH pathidx, const u8* pMem, u32 size)
SetTag(pMem);
incTag(16, 1);
//if (pathidx == GIF_PATH_3) {
switch(pathidx)
if(nloop > 0)
{
case GIF_PATH_1:
if (tag.FLG&2) GSTransferStatus.PTH1 = IMAGE_MODE;
else GSTransferStatus.PTH1 = TRANSFER_MODE;
break;
case GIF_PATH_2:
if (tag.FLG&2) GSTransferStatus.PTH2 = IMAGE_MODE;
else GSTransferStatus.PTH2 = TRANSFER_MODE;
break;
case GIF_PATH_3:
if (tag.FLG&2) GSTransferStatus.PTH3 = IMAGE_MODE;
else GSTransferStatus.PTH3 = TRANSFER_MODE;
break;
switch(pathidx)
{
case GIF_PATH_1:
if(tag.FLG & 2)GSTransferStatus.PTH1 = IMAGE_MODE;
else GSTransferStatus.PTH1 = TRANSFER_MODE;
break;
case GIF_PATH_2:
if(tag.FLG & 2)GSTransferStatus.PTH2 = IMAGE_MODE;
else GSTransferStatus.PTH2 = TRANSFER_MODE;
break;
case GIF_PATH_3:
if(tag.FLG & 2) GSTransferStatus.PTH3 = IMAGE_MODE;
else GSTransferStatus.PTH3 = TRANSFER_MODE;
break;
}
if(gifRegs->stat.DIR == 0)gifRegs->stat.OPH = true;
gifRegs->stat.APATH = pathidx + 1;
}
//}
if(pathidx == GIF_PATH_3) break;
}
else
{
gifRegs->stat.APATH = pathidx + 1;
if(gifRegs->stat.DIR == 0)gifRegs->stat.OPH = true;
switch(tag.FLG) {
case GIF_FLG_PACKED:
GIF_LOG("Packed Mode");
@ -409,7 +420,7 @@ __forceinline int GIFPath::ParseTag(GIF_PATH pathidx, const u8* pMem, u32 size)
}
if(pathidx == GIF_PATH_1)
{
if(nloop > 0 && size == 0 && !tag.EOP) //Need to check all of this, some cases VU will send info (like the BIOS) but be incomplete
if(size == 0 && (!tag.EOP || nloop > 0)) //Need to check all of this, some cases VU will send info (like the BIOS) but be incomplete
{
switch(tag.FLG)
{
@ -433,39 +444,45 @@ __forceinline int GIFPath::ParseTag(GIF_PATH pathidx, const u8* pMem, u32 size)
}
}
}
if (tag.EOP && !nloop) {
if (pathidx != GIF_PATH_2) {
break;
}
}
if (tag.EOP && !nloop) break;
}
/*if(((GSTransferStatus.PTH1 & 0x2) + (GSTransferStatus.PTH2 & 0x2) + ((GSTransferStatus.PTH3 & 0x2) && !vif1Regs->mskpath3)) < 0x4 )
Console.Warning("CHK PTH1 %x, PTH2 %x, PTH3 %x", GSTransferStatus.PTH1, GSTransferStatus.PTH2, GSTransferStatus.PTH3);*/
size = (startSize - size);
if (tag.EOP && !nloop) {
//Console.Warning("Finishing path %x", pathidx);
if (tag.EOP && nloop <= 16) {
if(pathidx == 2 && nloop > 0)
{
if(GSTransferStatus.PTH3 != IDLE_MODE) GSTransferStatus.PTH3 = PENDINGSTOP_MODE;
}
else if(nloop == 0)
{
if(gifRegs->stat.DIR == 0)gifRegs->stat.OPH = false;
gifRegs->stat.APATH = GIF_APATH_IDLE;
switch(pathidx)
{
case GIF_PATH_1:
GSTransferStatus.PTH1 = STOPPED_MODE;
break;
case GIF_PATH_2:
GSTransferStatus.PTH2 = STOPPED_MODE;
GSTransferStatus.PTH2 = PENDINGSTOP_MODE;
break;
case GIF_PATH_3:
GSTransferStatus.PTH3 = STOPPED_MODE;
if(GSTransferStatus.PTH3 != IDLE_MODE) GSTransferStatus.PTH3 = STOPPED_MODE;
break;
}
}
}
else if(nloop <= 16 && GSTransferStatus.PTH3 == IMAGE_MODE && pathidx == 2)
{
GSTransferStatus.PTH3 = PENDINGIMAGE_MODE;
}
if (pathidx == GIF_PATH_3 && gif->chcr.STR) { //Make sure we are really doing a DMA and not using FIFO
//GIF_LOG("Path3 end EOP %x NLOOP %x Status %x", tag.EOP, nloop, GSTransferStatus.PTH3);
gif->madr += size * 16;
gif->qwc -= size;
} else if (pathidx == GIF_PATH_2 && !nloop) { //Path2 is odd, but always provides the correct size
GSTransferStatus.PTH2 = STOPPED_MODE;
}
return size;
@ -476,7 +493,7 @@ __forceinline int GIFPath::ParseTag(GIF_PATH pathidx, const u8* pMem, u32 size)
// runs potentially several frames behind.
// Parameters:
// size - max size of incoming data stream, in qwc (simd128)
__forceinline int GIFPath_ParseTag(GIF_PATH pathidx, const u8* pMem, u32 size)
__forceinline int GIFPath_ParseTag(GIF_PATH pathidx, const u8* pMem, u32 size, bool TestOnly)
{
#ifdef PCSX2_GSRING_SAMPLING_STATS
static uptr profStartPtr = 0;
@ -492,7 +509,7 @@ __forceinline int GIFPath_ParseTag(GIF_PATH pathidx, const u8* pMem, u32 size)
}
#endif
int retSize = s_gifPath[pathidx].ParseTag(pathidx, pMem, size);
int retSize = s_gifPath[pathidx].ParseTag(pathidx, pMem, size, TestOnly);
#ifdef PCSX2_GSRING_SAMPLING_STATS
__asm
@ -515,6 +532,8 @@ void GIFPath_Reset()
__forceinline void GIFPath_Clear( GIF_PATH pathidx )
{
memzero(s_gifPath.path[pathidx]);
GSTransferStatus._u32 &= ~(0xf << (pathidx * 4));
GSTransferStatus._u32 |= (0x5 << (pathidx * 4));
if( GSgifSoftReset == NULL ) return;
GetMTGS().SendSimplePacket( GS_RINGTYPE_SOFTRESET, (1<<pathidx), 0, 0 );
}

View File

@ -15,6 +15,7 @@
#pragma once
#include "Gif.h"
//------------------------------------------------------------------
// Micro VU Micromode Lower instructions
//------------------------------------------------------------------
@ -1106,22 +1107,53 @@ void __fastcall mVU_XGKICK_(u32 addr) {
addr &= 0x3ff;
u8* data = microVU1.regs->Mem + (addr*16);
u32 diff = 0x400 - addr;
u32 size = GetMTGS().PrepDataPacket(GIF_PATH_1, data, diff);
u8* pDest = GetMTGS().GetDataPacketPtr();
u32 size;
u8* pDest;
if (size > diff) {
// fixme: one of these days the following *16's will get cleaned up when we introduce
// a special qwc/simd16 optimized version of memcpy_aligned. :)
//DevCon.Status("XGkick Wrap!");
memcpy_aligned(pDest, microVU1.regs->Mem + (addr*16), diff*16);
size -= diff;
pDest += diff*16;
memcpy_aligned(pDest, microVU1.regs->Mem, size*16);
if(gifRegs->stat.APATH == GIF_APATH_IDLE)
{
size = GetMTGS().PrepDataPacket(GIF_PATH_1, data, diff, false);
pDest = GetMTGS().GetDataPacketPtr();
if (size > diff) {
// fixme: one of these days the following *16's will get cleaned up when we introduce
// a special qwc/simd16 optimized version of memcpy_aligned. :)
//DevCon.Status("XGkick Wrap!");
memcpy_aligned(pDest, microVU1.regs->Mem + (addr*16), diff*16);
size -= diff;
pDest += diff*16;
memcpy_aligned(pDest, microVU1.regs->Mem, size*16);
}
else {
memcpy_aligned(pDest, microVU1.regs->Mem + (addr*16), size*16);
}
GetMTGS().SendDataPacket();
}
else {
memcpy_aligned(pDest, microVU1.regs->Mem + (addr*16), size*16);
else
{
//DevCon.Warning("GIF APATH busy %x Holding for later W %x, R %x", gifRegs->stat.APATH, Path1WritePos, Path1ReadPos);
size = GetMTGS().PrepDataPacket(GIF_PATH_1, data, diff, true);
pDest = &Path1Buffer[Path1WritePos*16];
//DevCon.Warning("Storing size %x PATH 1", size);
if (size > diff) {
// fixme: one of these days the following *16's will get cleaned up when we introduce
// a special qwc/simd16 optimized version of memcpy_aligned. :)
//DevCon.Status("XGkick Wrap!");
memcpy_aligned(pDest, microVU1.regs->Mem + (addr*16), diff*16);
Path1WritePos += size;
size -= diff;
pDest += diff*16;
memcpy_aligned(pDest, microVU1.regs->Mem, size*16);
}
else {
memcpy_aligned(pDest, microVU1.regs->Mem + (addr*16), size*16);
Path1WritePos += size;
}
if(!gifRegs->stat.P1Q) CPU_INT(28, 16);
gifRegs->stat.P1Q = true;
}
GetMTGS().SendDataPacket();
}
_f void mVU_XGKICK_DELAY(mV, bool memVI) {

View File

@ -87,6 +87,7 @@ struct nVifStruct {
u8* vuMemEnd; // End of VU Memory
u32 vuMemLimit; // Use for fast AND
u32 bSize; // Size of 'buffer'
u32 bPtr;
u8 buffer[_1mb]; // Buffer for partial transfers
u8* recPtr; // Cur Pos to recompile to
u8* recEnd; // 'Safe' End of Rec Cache

View File

@ -173,7 +173,7 @@ void VifUnpackSSE_Dynarec::CompileRoutine() {
if (++vCL == blockSize) vCL = 0;
}
else if (isFill) {
DevCon.WriteLn("filling mode!");
//DevCon.WriteLn("filling mode!");
VifUnpackSSE_Dynarec fill( VifUnpackSSE_Dynarec::FillingWrite( *this ) );
fill.xUnpack(upkNum);
fill.xMovDest();

View File

@ -26,6 +26,7 @@
#include "sVU_Micro.h"
#include "sVU_Debug.h"
#include "sVU_zerorec.h"
#include "Gif.h"
//------------------------------------------------------------------
//------------------------------------------------------------------
@ -1971,27 +1972,57 @@ void recVUMI_XTOP( VURegs *VU, int info )
//------------------------------------------------------------------
void __fastcall VU1XGKICK_MTGSTransfer(u32 *pMem, u32 addr)
{
addr &= 0x3fff;
u8* data = VU1.Mem + (addr);
u32 diff = 0x400 - (addr / 16);
u32 size;
u8* data = ((u8*)pMem + (addr&0x3fff));
u8* pDest;
size = GetMTGS().PrepDataPacket(GIF_PATH_1, data, (0x4000-(addr&0x3fff)) / 16);
jASSUME( size > 0 );
u8* pmem = GetMTGS().GetDataPacketPtr();
if((size << 4) > (0x4000-(addr&0x3fff)))
if(gifRegs->stat.APATH == GIF_APATH_IDLE)
{
//DevCon.Warning("addr + Size = 0x%x, transferring %x then doing %x", (addr&0x3fff) + (size << 4), (0x4000-(addr&0x3fff)) >> 4, size - ((0x4000-(addr&0x3fff)) >> 4));
memcpy_aligned(pmem, (u8*)pMem+addr, 0x4000-(addr&0x3fff));
size -= (0x4000-(addr&0x3fff)) >> 4;
//DevCon.Warning("Size left %x", size);
pmem += 0x4000-(addr&0x3fff);
memcpy_aligned(pmem, (u8*)pMem, size<<4);
size = GetMTGS().PrepDataPacket(GIF_PATH_1, data, diff, false);
pDest = GetMTGS().GetDataPacketPtr();
if (size > diff) {
// fixme: one of these days the following *16's will get cleaned up when we introduce
// a special qwc/simd16 optimized version of memcpy_aligned. :)
memcpy_aligned(pDest, VU1.Mem + addr, diff*16);
size -= diff;
pDest += diff*16;
memcpy_aligned(pDest, VU1.Mem, size*16);
}
else {
memcpy_aligned(pDest, VU1.Mem + addr, size*16);
}
GetMTGS().SendDataPacket();
}
else {
memcpy_aligned(pmem, (u8*)pMem+addr, size<<4);
else
{
//DevCon.Warning("GIF APATH busy %x Holding for later W %x, R %x", gifRegs->stat.APATH, Path1WritePos, Path1ReadPos);
size = GetMTGS().PrepDataPacket(GIF_PATH_1, data, diff, true);
pDest = &Path1Buffer[Path1WritePos*16];
//DevCon.Warning("Storing size %x PATH 1", size);
if (size > diff) {
// fixme: one of these days the following *16's will get cleaned up when we introduce
// a special qwc/simd16 optimized version of memcpy_aligned. :)
//DevCon.Status("XGkick Wrap!");
memcpy_aligned(pDest, VU1.Mem + addr, diff*16);
Path1WritePos += size;
size -= diff;
pDest += diff*16;
memcpy_aligned(pDest, VU1.Mem, size*16);
}
else {
memcpy_aligned(pDest, VU1.Mem + addr, size*16);
Path1WritePos += size;
}
if(!gifRegs->stat.P1Q) CPU_INT(28, 16);
gifRegs->stat.P1Q = true;
}
GetMTGS().SendDataPacket();
}
//------------------------------------------------------------------