-Fixed a small bug in the unpack dynarec causing it to drop back to the interpreter (MGS3 - now about 10fps faster!)

-Rewrote VIF0 DMA to work like VIF1, report any breakage from it.
-Tweaked a couple of cycle bits when stalling VIF

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2766 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
refraction 2010-03-26 00:06:29 +00:00
parent b1e6094408
commit 928816732b
4 changed files with 118 additions and 82 deletions

View File

@ -143,13 +143,8 @@ _f void vif0FBRST(u32 value) {
g_vifCycles = 0;
// loop necessary for spiderman
if (vif0.stallontag)
_chainVIF0();
else
_VIF0chain();
vif0ch->chcr.STR = true;
CPU_INT(DMAC_VIF0, g_vifCycles); // Gets the timing right - Flatout
CPU_INT(DMAC_VIF0, 0); // Gets the timing right - Flatout
}
}
}
@ -225,14 +220,14 @@ _f void vif1FBRST(u32 value) {
{
case MFD_VIF1:
//Console.WriteLn("MFIFO Stall");
CPU_INT(10, vif1ch->qwc * BIAS);
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, vif1ch->qwc * BIAS);
CPU_INT(DMAC_VIF1, 0);
break;
}

View File

@ -29,11 +29,15 @@ __forceinline void vif0FLUSH()
g_vifCycles += (VU0.cycle - _cycles) * BIAS;
}
bool _VIF0chain()
bool _VIF0chain()
{
u32 *pMem;
if ((vif0ch->qwc == 0) && !vif0.vifstalled) return true;
if (vif0ch->qwc == 0)
{
vif0.inprogress = 0;
return true;
}
pMem = (u32*)dmaGetAddr(vif0ch->madr);
if (pMem == NULL)
@ -44,88 +48,115 @@ bool _VIF0chain()
return true;
}
VIF_LOG("VIF0chain size=%d, madr=%lx, tadr=%lx",
vif0ch->qwc, vif0ch->madr, vif0ch->tadr);
if (vif0.vifstalled)
return VIF0transfer(pMem + vif0.irqoffset, vif0ch->qwc * 4 - vif0.irqoffset, false);
else
return VIF0transfer(pMem, vif0ch->qwc * 4, false);
}
bool _chainVIF0()
__forceinline void vif0SetupTransfer()
{
tDMA_TAG *ptag;
ptag = dmaGetAddr(vif0ch->tadr); //Set memory pointer to TADR
if (!(vif0ch->transfer("Vif0 Tag", ptag))) return false;
vif0ch->madr = ptag[1]._u32; // MADR = ADDR field + SPR
g_vifCycles += 1; // Increase the QW read for the tag
VIF_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx",
ptag[1]._u32, ptag[0]._u32, vif0ch->qwc, ptag->ID, vif0ch->madr, vif0ch->tadr);
// Transfer dma tag if tte is set
if (vif0ch->chcr.TTE)
switch (vif0.dmamode)
{
bool ret;
case VIF_NORMAL_TO_MEM_MODE:
vif0.inprogress = 1;
vif0.done = true;
g_vifCycles = 2;
break;
if (vif0.vifstalled)
ret = VIF0transfer((u32*)ptag + (2 + vif0.irqoffset), 2 - vif0.irqoffset, true); //Transfer Tag on stall
else
ret = VIF0transfer((u32*)ptag + 2, 2, true); //Transfer Tag
case VIF_CHAIN_MODE:
ptag = dmaGetAddr(vif0ch->tadr); //Set memory pointer to TADR
if (!(ret)) return false; //IRQ set by VIFTransfer
if (!(vif0ch->transfer("vif0 Tag", ptag))) return;
vif0ch->madr = ptag[1]._u32; //MADR = ADDR field + SPR
g_vifCycles += 1; // Add 1 g_vifCycles from the QW read for the tag
// Transfer dma tag if tte is set
VIF_LOG("vif0 Tag %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx\n",
ptag[1]._u32, ptag[0]._u32, vif0ch->qwc, ptag->ID, vif0ch->madr, vif0ch->tadr);
vif0.inprogress = 1;
if (vif0ch->chcr.TTE)
{
bool ret;
if (vif0.vifstalled)
ret = VIF0transfer((u32*)ptag + (2 + vif0.irqoffset), 2 - vif0.irqoffset, true); //Transfer Tag on stall
else
ret = VIF0transfer((u32*)ptag + 2, 2, true); //Transfer Tag
if ((ret == false) && vif0.irqoffset < 2)
{
vif0.inprogress = 0; //Better clear this so it has to do it again (Jak 1)
return; //There has been an error or an interrupt
}
}
vif0.irqoffset = 0;
vif0.done |= hwDmacSrcChainWithStack(vif0ch, ptag->ID);
//Check TIE bit of CHCR and IRQ bit of tag
if (vif0ch->chcr.TIE && ptag->IRQ)
{
VIF_LOG("dmaIrq Set");
//End Transfer
vif0.done = true;
return;
}
break;
}
vif0.done |= hwDmacSrcChainWithStack(vif0ch, ptag->ID);
VIF_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx",
ptag[1]._u32, ptag[0]._u32, vif0ch->qwc, ptag->ID, vif0ch->madr, vif0ch->tadr);
_VIF0chain(); //Transfers the data set by the switch
if (vif0ch->chcr.TIE && ptag->IRQ) //Check TIE bit of CHCR and IRQ bit of tag
{
VIF_LOG("dmaIrq Set\n");
vif0.done = true; //End Transfer
}
return vif0.done;
}
void vif0Interrupt()
__forceinline void vif0Interrupt()
{
g_vifCycles = 0; //Reset the cycle count, Wouldn't reset on stall if put lower down.
VIF_LOG("vif0Interrupt: %8.8x", cpuRegs.cycle);
if (vif0.irq && (vif0.tag.size == 0))
g_vifCycles = 0;
if (!(vif0ch->chcr.STR)) Console.WriteLn("vif0 running when CHCR == %x", vif0ch->chcr._u32);
if (vif0.irq && vif0.tag.size == 0)
{
vif0Regs->stat.INT = true;
hwIntcIrq(VIF0intc);
--vif0.irq;
if (vif0Regs->stat.test(VIF0_STAT_VSS | VIF0_STAT_VIS | VIF0_STAT_VFS))
{
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;
}
if (vif0ch->qwc > 0 || vif0.irqoffset > 0)
else if ((vif0ch->qwc > 0) || (vif0.irqoffset > 0))
{
if (vif0.stallontag)
_chainVIF0();
vif0SetupTransfer();
else
_VIF0chain();
CPU_INT(DMAC_VIF0, /*g_vifCycles*/ VifCycleVoodoo);
return;
_VIF0chain();//CPU_INT(DMAC_STALL_SIS, vif0ch->qwc * BIAS);
}
}
if (!vif0ch->chcr.STR) Console.WriteLn("Vif0 running when CHCR = %x", vif0ch->chcr._u32);
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*/ VifCycleVoodoo);
return;
}
if ((vif0ch->chcr.MOD == CHAIN_MODE) && (!vif0.done))
if (!vif0.done)
{
if (!(dmacRegs->ctrl.DMAE))
@ -134,19 +165,26 @@ void vif0Interrupt()
return;
}
if (vif0ch->qwc > 0)
_VIF0chain();
else
_chainVIF0();
if ((vif0.inprogress & 0x1) == 0) vif0SetupTransfer();
CPU_INT(DMAC_VIF0, /*g_vifCycles*/ VifCycleVoodoo);
return;
}
if (vif0ch->qwc > 0) Console.WriteLn("VIF0 Ending with QWC left");
if (vif0.cmd != 0) Console.WriteLn("vif0.cmd still set %x", vif0.cmd);
if (vif0.vifstalled && vif0.irq)
{
DevCon.WriteLn("VIF0 looping on stall\n");
CPU_INT(DMAC_VIF0, 0);
return; //Dont want to end if vif is stalled.
}
#ifdef PCSX2_DEVBUILD
if (vif0ch->qwc > 0) Console.WriteLn("vif0 Ending with %x QWC left");
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);
vif0Regs->stat.FQC = 0;
}
@ -154,30 +192,28 @@ void vif0Interrupt()
void dmaVIF0()
{
VIF_LOG("dmaVIF0 chcr = %lx, madr = %lx, qwc = %lx\n"
" tadr = %lx, asr0 = %lx, asr1 = %lx\n",
" tadr = %lx, asr0 = %lx, asr1 = %lx",
vif0ch->chcr._u32, vif0ch->madr, vif0ch->qwc,
vif0ch->tadr, vif0ch->asr0, vif0ch->asr1);
g_vifCycles = 0;
vif0.inprogress = 0;
vif0Regs->stat.FQC = 0x8; // FQC=8
if (!(vif0ch->chcr.MOD & 0x1) || vif0ch->qwc > 0) // Normal Mode
if ((vif0ch->chcr.MOD == NORMAL_MODE) || vif0ch->qwc > 0) // Normal Mode
{
if (!_VIF0chain())
{
Console.WriteLn(L"Stall on normal vif0 " + vif0Regs->stat.desc());
vif0.vifstalled = true;
return;
}
vif0.done = true;
CPU_INT(DMAC_VIF0, /*g_vifCycles*/ VifCycleVoodoo);
return;
vif0.dmamode = VIF_NORMAL_TO_MEM_MODE;
}
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);
// Chain Mode
vif0.done = false;
CPU_INT(DMAC_VIF0, 0);
}
vif0Interrupt();
}

View File

@ -262,6 +262,7 @@ __forceinline void vif1Interrupt()
if (vif1.vifstalled && vif1.irq)
{
DevCon.WriteLn("VIF1 looping on stall\n");
CPU_INT(DMAC_VIF1, 0);
return; //Dont want to end if vif is stalled.
}

View File

@ -186,12 +186,16 @@ static _f u8* dVifsetVUptr(const nVifStruct& v, int cl, int wl, bool isFill) {
if (!isFill) { // Account for skip-cycles
int skipSize = cl - wl;
int blocks = _vBlock.num / wl;
int skips = (blocks * skipSize + _vBlock.num) * 16;
int skips = (blocks * skipSize + _vBlock.num) * 16;
//We must do skips - 1 here else skip calculation adds an extra skip which can overflow
//causing the emu to drop back to the interpreter (do not need to skip on last block write) - Refraction
if(skipSize > 0) skips -= skipSize * 16;
endPtr = ptr + skips;
}
else endPtr = ptr + (_vBlock.num * 16);
if ( endPtr > v.vuMemEnd ) {
DevCon.WriteLn("nVif - VU Mem Ptr Overflow; falling back to interpreter.");
DevCon.WriteLn("nVif%x - VU Mem Ptr Overflow; falling back to interpreter. Start = %x End = %x num = %x, wl = %x, cl = %x", v.idx, v.vif->tag.addr, v.vif->tag.addr + (_vBlock.num * 16), _vBlock.num, wl, cl);
ptr = NULL; // Fall Back to Interpreters which have wrap-around logic
}
return ptr;