From 92ddae17ce197486731099b0e46ab4105aff2067 Mon Sep 17 00:00:00 2001 From: cottonvibes Date: Sat, 23 Jan 2010 04:14:59 +0000 Subject: [PATCH] More vif refactoring/cleanups. There is a lot of code duplication in the vif0/vif1 files, I will probably work on getting them to use common functions. git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2489 96395faa-99c1-11dd-bbfe-3dabce05a288 --- pcsx2/Gif.cpp | 2 +- pcsx2/Hardware.h | 2 +- pcsx2/Vif.cpp | 316 +--- pcsx2/Vif.h | 16 +- pcsx2/Vif0_Commands.cpp | 275 +++ pcsx2/{Vif0Dma.cpp => Vif0_Dma.cpp} | 1192 +++++-------- pcsx2/Vif1_Commands.cpp | 425 +++++ pcsx2/{Vif1Dma.cpp => Vif1_Dma.cpp} | 1824 ++++++++------------ pcsx2/Vif1_MFIFO.cpp | 305 ++++ pcsx2/VifDma_internal.h | 20 - pcsx2/{VifDma.cpp => Vif_Commands.cpp} | 118 +- pcsx2/{VifDma.h => Vif_Dma.h} | 179 +- pcsx2/Vif_Unpack.cpp | 2 +- pcsx2/ps2/GIFpath.cpp | 2 +- pcsx2/windows/VCprojects/pcsx2_2008.vcproj | 20 +- pcsx2/x86/newVif_Dynarec.cpp | 2 +- pcsx2/x86/newVif_Unpack.cpp | 2 +- pcsx2/x86/newVif_UnpackSSE.h | 2 +- 18 files changed, 2354 insertions(+), 2350 deletions(-) create mode 100644 pcsx2/Vif0_Commands.cpp rename pcsx2/{Vif0Dma.cpp => Vif0_Dma.cpp} (54%) create mode 100644 pcsx2/Vif1_Commands.cpp rename pcsx2/{Vif1Dma.cpp => Vif1_Dma.cpp} (56%) create mode 100644 pcsx2/Vif1_MFIFO.cpp delete mode 100644 pcsx2/VifDma_internal.h rename pcsx2/{VifDma.cpp => Vif_Commands.cpp} (78%) rename pcsx2/{VifDma.h => Vif_Dma.h} (82%) diff --git a/pcsx2/Gif.cpp b/pcsx2/Gif.cpp index 01475d2ee7..d79bb5966f 100644 --- a/pcsx2/Gif.cpp +++ b/pcsx2/Gif.cpp @@ -18,7 +18,7 @@ #include "GS.h" #include "Gif.h" -#include "VifDma.h" +#include "Vif_Dma.h" #include "iR5900.h" diff --git a/pcsx2/Hardware.h b/pcsx2/Hardware.h index e4edff6056..4cbe475839 100644 --- a/pcsx2/Hardware.h +++ b/pcsx2/Hardware.h @@ -25,6 +25,6 @@ #include "Gif.h" #include "Sif.h" #include "Vif.h" -#include "VifDma.h" +#include "Vif_Dma.h" #endif diff --git a/pcsx2/Vif.cpp b/pcsx2/Vif.cpp index df428f4d0d..49c48aefda 100644 --- a/pcsx2/Vif.cpp +++ b/pcsx2/Vif.cpp @@ -13,296 +13,72 @@ * If not, see . */ - #include "PrecompiledHeader.h" #include "Common.h" - -#include - #include "Vif.h" -#include "VifDma.h" +#include "Vif_Dma.h" -VIFregisters *vifRegs; -vifStruct *vif; -u16 vifqwc = 0; +void vif0Init() { initNewVif(0); } +void vif1Init() { initNewVif(1); } -__aligned16 VifMaskTypes g_vifmask; - -extern int g_vifCycles; - -static __forceinline bool mfifoVIF1rbTransfer() +void vif0Reset() { - u32 maddr = dmacRegs->rbor.ADDR; - u32 msize = dmacRegs->rbor.ADDR + dmacRegs->rbsr.RMSK + 16; - u16 mfifoqwc = std::min(vif1ch->qwc, vifqwc); - u32 *src; - bool ret; + /* Reset the whole VIF, meaning the internal pcsx2 vars and all the registers */ + memzero(vif0); + memzero(*vif0Regs); - /* Check if the transfer should wrap around the ring buffer */ - if ((vif1ch->madr + (mfifoqwc << 4)) > (msize)) - { - int s1 = ((msize) - vif1ch->madr) >> 2; + psHu64(VIF0_FIFO) = 0; + psHu64(VIF0_FIFO + 8) = 0; + + vif0Regs->stat.VPS = VPS_IDLE; + vif0Regs->stat.FQC = 0; - SPR_LOG("Split MFIFO"); + vif0.done = true; - /* it does, so first copy 's1' bytes from 'addr' to 'data' */ - src = (u32*)PSM(vif1ch->madr); - if (src == NULL) return false; - - if (vif1.vifstalled) - ret = VIF1transfer(src + vif1.irqoffset, s1 - vif1.irqoffset, false); - else - ret = VIF1transfer(src, s1, false); - - if (ret) - { - /* and second copy 's2' bytes from 'maddr' to '&data[s1]' */ - vif1ch->madr = maddr; - - src = (u32*)PSM(maddr); - if (src == NULL) return false; - VIF1transfer(src, ((mfifoqwc << 2) - s1), false); - } - } - else - { - SPR_LOG("Direct MFIFO"); - - /* it doesn't, so just transfer 'qwc*4' words */ - src = (u32*)PSM(vif1ch->madr); - if (src == NULL) return false; - - if (vif1.vifstalled) - ret = VIF1transfer(src + vif1.irqoffset, mfifoqwc * 4 - vif1.irqoffset, false); - else - ret = VIF1transfer(src, mfifoqwc << 2, false); - } - return ret; + resetNewVif(0); } -static __forceinline bool mfifo_VIF1chain() +void vif1Reset() { - bool ret; - - /* Is QWC = 0? if so there is nothing to transfer */ - if ((vif1ch->qwc == 0) && (!vif1.vifstalled)) - { - vif1.inprogress &= ~1; - return true; - } + /* Reset the whole VIF, meaning the internal pcsx2 vars, and all the registers */ + memzero(vif1); + memzero(*vif1Regs); - if (vif1ch->madr >= dmacRegs->rbor.ADDR && - vif1ch->madr <= (dmacRegs->rbor.ADDR + dmacRegs->rbsr.RMSK)) - { - u16 startqwc = vif1ch->qwc; - ret = mfifoVIF1rbTransfer(); - vifqwc -= startqwc - vif1ch->qwc; - } - else - { - tDMA_TAG *pMem = dmaGetAddr(vif1ch->madr); - SPR_LOG("Non-MFIFO Location"); + psHu64(VIF1_FIFO) = 0; + psHu64(VIF1_FIFO + 8) = 0; - if (pMem == NULL) return false; + vif1Regs->stat.VPS = VPS_IDLE; + vif1Regs->stat.FQC = 0; // FQC=0 - if (vif1.vifstalled) - ret = VIF1transfer((u32*)pMem + vif1.irqoffset, vif1ch->qwc * 4 - vif1.irqoffset, false); - else - ret = VIF1transfer((u32*)pMem, vif1ch->qwc << 2, false); - } - return ret; + vif1.done = true; + cpuRegs.interrupt &= ~((1 << 1) | (1 << 10)); //Stop all vif1 DMA's + + resetNewVif(1); } -static u32 qwctag(u32 mask) +void SaveStateBase::vif0Freeze() { - return (dmacRegs->rbor.ADDR + (mask & dmacRegs->rbsr.RMSK)); + static u32 g_vif0Masks[64]; // Dummy Var for saved state compatibility + static u32 g_vif0HasMask3[4]; // Dummy Var for saved state compatibility + FreezeTag("VIFdma"); + + // Dunno if this one is needed, but whatever, it's small. :) + Freeze(g_vifCycles); + + // mask settings for VIF0 and VIF1 + Freeze(g_vifmask); + + Freeze(vif0); + Freeze(g_vif0HasMask3); // Not Used Anymore + Freeze(g_vif0Masks); // Not Used Anymore } -void mfifoVIF1transfer(int qwc) +void SaveStateBase::vif1Freeze() { - tDMA_TAG *ptag; + static u32 g_vif1Masks[64]; // Dummy Var for saved state compatibility + static u32 g_vif1HasMask3[4]; // Dummy Var for saved state compatibility + Freeze(vif1); - g_vifCycles = 0; - - if (qwc > 0) - { - vifqwc += qwc; - SPR_LOG("Added %x qw to mfifo, total now %x - Vif CHCR %x Stalled %x done %x", qwc, vifqwc, vif1ch->chcr._u32, vif1.vifstalled, vif1.done); - if (vif1.inprogress & 0x10) - { - if (vif1ch->madr >= dmacRegs->rbor.ADDR && vif1ch->madr <= (dmacRegs->rbor.ADDR + dmacRegs->rbsr.RMSK)) - CPU_INT(10, 0); - else - CPU_INT(10, vif1ch->qwc * BIAS); - - vif1Regs->stat.FQC = 0x10; // FQC=16 - } - vif1.inprogress &= ~0x10; - - return; - } - - if (vif1ch->qwc == 0 && vifqwc > 0) - { - ptag = dmaGetAddr(vif1ch->tadr); - - if (vif1ch->chcr.TTE) - { - bool ret; - - if (vif1.stallontag) - ret = VIF1transfer((u32*)ptag + (2 + vif1.irqoffset), 2 - vif1.irqoffset, true); //Transfer Tag on Stall - else - ret = VIF1transfer((u32*)ptag + 2, 2, true); //Transfer Tag - - if (!(ret)) - { - VIF_LOG("MFIFO Stall on tag"); - vif1.stallontag = true; - return; //IRQ set by VIFTransfer - } - } - - vif1ch->unsafeTransfer(ptag); - - vif1ch->madr = ptag[1]._u32; - vifqwc--; - - SPR_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx mfifo qwc = %x spr0 madr = %x", - ptag[1]._u32, ptag[0]._u32, vif1ch->qwc, ptag->ID, vif1ch->madr, vif1ch->tadr, vifqwc, spr0->madr); - - switch (ptag->ID) - { - case TAG_REFE: // Refe - Transfer Packet According to ADDR field - vif1ch->tadr = qwctag(vif1ch->tadr + 16); - vif1.done = true; //End Transfer - break; - - case TAG_CNT: // CNT - Transfer QWC following the tag. - vif1ch->madr = qwctag(vif1ch->tadr + 16); //Set MADR to QW after Tag - vif1ch->tadr = qwctag(vif1ch->madr + (vif1ch->qwc << 4)); //Set TADR to QW following the data - vif1.done = false; - break; - - case TAG_NEXT: // Next - Transfer QWC following tag. TADR = ADDR - { - int temp = vif1ch->madr; //Temporarily Store ADDR - vif1ch->madr = qwctag(vif1ch->tadr + 16); //Set MADR to QW following the tag - vif1ch->tadr = temp; //Copy temporarily stored ADDR to Tag - if ((temp & dmacRegs->rbsr.RMSK) != dmacRegs->rbor.ADDR) Console.WriteLn("Next tag = %x outside ring %x size %x", temp, psHu32(DMAC_RBOR), psHu32(DMAC_RBSR)); - vif1.done = false; - break; - } - - case TAG_REF: // Ref - Transfer QWC from ADDR field - case TAG_REFS: // Refs - Transfer QWC from ADDR field (Stall Control) - vif1ch->tadr = qwctag(vif1ch->tadr + 16); //Set TADR to next tag - vif1.done = false; - break; - - case TAG_END: // End - Transfer QWC following the tag - vif1ch->madr = qwctag(vif1ch->tadr + 16); //Set MADR to data following the tag - vif1ch->tadr = qwctag(vif1ch->madr + (vif1ch->qwc << 4)); //Set TADR to QW following the data - vif1.done = true; //End Transfer - break; - } - - if (vif1ch->chcr.TIE && ptag->IRQ) - { - VIF_LOG("dmaIrq Set"); - vif1.done = true; - } - } - - vif1.inprogress |= 1; - - SPR_LOG("mfifoVIF1transfer end %x madr %x, tadr %x vifqwc %x", vif1ch->chcr._u32, vif1ch->madr, vif1ch->tadr, vifqwc); -} - -void vifMFIFOInterrupt() -{ - g_vifCycles = 0; - - if (schedulepath3msk) Vif1MskPath3(); - - if ((vif1Regs->stat.VGW)) - { - if (gif->chcr.STR) - { - CPU_INT(10, 16); - return; - } - else - { - vif1Regs->stat.VGW = false; - } - - } - - if ((spr0->chcr.STR) && (spr0->qwc == 0)) - { - spr0->chcr.STR = false; - hwDmacIrq(DMAC_FROM_SPR); - } - - if (vif1.irq && vif1.tag.size == 0) - { - vif1Regs->stat.INT = true; - hwIntcIrq(INTC_VIF1); - --vif1.irq; - - if (vif1Regs->stat.test(VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS)) - { - vif1Regs->stat.FQC = 0; // FQC=0 - vif1ch->chcr.STR = false; - return; - } - } - - if (vif1.done == false || vif1ch->qwc) - { - switch(vif1.inprogress & 1) - { - case 0: //Set up transfer - if (vif1ch->tadr == spr0->madr) - { - // Console.WriteLn("Empty 1"); - vifqwc = 0; - vif1.inprogress |= 0x10; - vif1Regs->stat.FQC = 0; - hwDmacIrq(DMAC_MFIFO_EMPTY); - return; - } - - mfifoVIF1transfer(0); - if ((vif1ch->madr >= dmacRegs->rbor.ADDR) && (vif1ch->madr <= (dmacRegs->rbor.ADDR + dmacRegs->rbsr.RMSK))) - CPU_INT(10, 0); - else - CPU_INT(10, vif1ch->qwc * BIAS); - - return; - - case 1: //Transfer data - mfifo_VIF1chain(); - CPU_INT(10, 0); - return; - } - return; - } - - /*if (vifqwc <= 0) - { - //Console.WriteLn("Empty 2"); - //vif1.inprogress |= 0x10; - vif1Regs->stat.FQC = 0; // FQC=0 - hwDmacIrq(DMAC_MFIFO_EMPTY); - }*/ - - vif1.done = 1; - g_vifCycles = 0; - vif1ch->chcr.STR = false; - hwDmacIrq(DMAC_VIF1); - VIF_LOG("vif mfifo dma end"); - - vif1Regs->stat.FQC = 0; + Freeze(g_vif1HasMask3); // Not Used Anymore + Freeze(g_vif1Masks); // Not Used Anymore } diff --git a/pcsx2/Vif.h b/pcsx2/Vif.h index 26e7df1c96..ac0203705c 100644 --- a/pcsx2/Vif.h +++ b/pcsx2/Vif.h @@ -13,8 +13,7 @@ * If not, see . */ -#ifndef __VIF_H__ -#define __VIF_H__ +#pragma once enum vif0_stat_flags { @@ -225,16 +224,3 @@ extern bool VIF0transfer(u32 *data, int size, bool istag); extern bool VIF1transfer(u32 *data, int size, bool istag); extern void vifMFIFOInterrupt(); -// -------------------------------------------------------------------------------------- -// newVif SSE-optimized Row/Col Structs -// -------------------------------------------------------------------------------------- - -struct VifMaskTypes -{ - u32 Row0[4], Col0[4]; - u32 Row1[4], Col1[4]; -}; - -extern __aligned16 VifMaskTypes g_vifmask; // This struct is used by newVif - -#endif /* __VIF_H__ */ diff --git a/pcsx2/Vif0_Commands.cpp b/pcsx2/Vif0_Commands.cpp new file mode 100644 index 0000000000..e5d852609a --- /dev/null +++ b/pcsx2/Vif0_Commands.cpp @@ -0,0 +1,275 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2009 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#include "PrecompiledHeader.h" +#include "Common.h" +#include "Vif_Dma.h" +#include "VUmicro.h" + +//------------------------------------------------------------------ +// Vif0 Data Transfer Commands +//------------------------------------------------------------------ + +static int __fastcall Vif0TransNull(u32 *data) // Shouldnt go here +{ + Console.WriteLn("VIF0 Shouldn't go here CMD = %x", vif0Regs->code); + vif0.cmd = 0; + return 0; +} + +static int __fastcall Vif0TransSTMask(u32 *data) // STMASK +{ + vif0Regs->mask = data[0]; + VIF_LOG("STMASK == %x", vif0Regs->mask); + + vif0.tag.size = 0; + vif0.cmd = 0; + return 1; +} + +static int __fastcall Vif0TransSTRow(u32 *data) // STROW +{ + int ret; + + u32* pmem = &vif0Regs->r0 + (vif0.tag.addr << 2); + u32* pmem2 = g_vifmask.Row0 + vif0.tag.addr; + pxAssume(vif0.tag.addr < 4); + ret = min(4 - vif0.tag.addr, vif0.vifpacketsize); + pxAssume(ret > 0); + + switch (ret) + { + case 4: + pmem[12] = data[3]; + pmem2[3] = data[3]; + case 3: + pmem[8] = data[2]; + pmem2[2] = data[2]; + case 2: + pmem[4] = data[1]; + pmem2[1] = data[1]; + case 1: + pmem[0] = data[0]; + pmem2[0] = data[0]; + break; + + jNO_DEFAULT + } + + vif0.tag.addr += ret; + vif0.tag.size -= ret; + if (vif0.tag.size == 0) vif0.cmd = 0; + + return ret; +} + +static int __fastcall Vif0TransSTCol(u32 *data) // STCOL +{ + int ret; + + u32* pmem = &vif0Regs->c0 + (vif0.tag.addr << 2); + u32* pmem2 = g_vifmask.Col0 + vif0.tag.addr; + ret = min(4 - vif0.tag.addr, vif0.vifpacketsize); + + switch (ret) + { + case 4: + pmem[12] = data[3]; + pmem2[3] = data[3]; + case 3: + pmem[8] = data[2]; + pmem2[2] = data[2]; + case 2: + pmem[4] = data[1]; + pmem2[1] = data[1]; + case 1: + pmem[0] = data[0]; + pmem2[0] = data[0]; + break; + + jNO_DEFAULT + } + + vif0.tag.addr += ret; + vif0.tag.size -= ret; + if (vif0.tag.size == 0) vif0.cmd = 0; + return ret; +} + +static __forceinline void vif0mpgTransfer(u32 addr, u32 *data, int size) +{ + if (memcmp(VU0.Micro + addr, data, size << 2)) + { + CpuVU0->Clear(addr, size << 2); // Clear before writing! :/ (cottonvibes) + memcpy_fast(VU0.Micro + addr, data, size << 2); + } +} + +static int __fastcall Vif0TransMPG(u32 *data) // MPG +{ + if (vif0.vifpacketsize < vif0.tag.size) + { + if((vif0.tag.addr + vif0.vifpacketsize) > 0x1000) DevCon.Warning("Vif0 MPG Split Overflow"); + + vif0mpgTransfer(vif0.tag.addr, data, vif0.vifpacketsize); + vif0.tag.addr += vif0.vifpacketsize << 2; + vif0.tag.size -= vif0.vifpacketsize; + + return vif0.vifpacketsize; + } + else + { + int ret; + + if((vif0.tag.addr + vif0.tag.size) > 0x1000) DevCon.Warning("Vif0 MPG Overflow"); + + vif0mpgTransfer(vif0.tag.addr, data, vif0.tag.size); + ret = vif0.tag.size; + vif0.tag.size = 0; + vif0.cmd = 0; + + return ret; + } +} + +static int __fastcall Vif0TransUnpack(u32 *data) // UNPACK +{ + return nVifUnpack(0, (u8*)data); +} + +//------------------------------------------------------------------ +// Vif0 CMD Base Commands +//------------------------------------------------------------------ + +static void Vif0CMDNop() // NOP +{ + vif0.cmd &= ~0x7f; +} + +static void Vif0CMDSTCycl() // STCYCL +{ + vif0Regs->cycle.cl = (u8)vif0Regs->code; + vif0Regs->cycle.wl = (u8)(vif0Regs->code >> 8); + vif0.cmd &= ~0x7f; +} + +static void Vif0CMDITop() // ITOP +{ + vif0Regs->itops = vif0Regs->code & 0x3ff; + vif0.cmd &= ~0x7f; +} + +static void Vif0CMDSTMod() // STMOD +{ + vif0Regs->mode = vif0Regs->code & 0x3; + vif0.cmd &= ~0x7f; +} + +static void Vif0CMDMark() // MARK +{ + vif0Regs->mark = (u16)vif0Regs->code; + vif0Regs->stat.MRK = true; + vif0.cmd &= ~0x7f; +} + +static void Vif0CMDFlushE() // FLUSHE +{ + vif0FLUSH(); + vif0.cmd &= ~0x7f; +} + +static void Vif0CMDMSCALF() //MSCAL/F +{ + vuExecMicro<0>((u16)(vif0Regs->code) << 3); + vif0.cmd &= ~0x7f; +} + +static void Vif0CMDMSCNT() // MSCNT +{ + vuExecMicro<0>(-1); + vif0.cmd &= ~0x7f; +} + +static void Vif0CMDSTMask() // STMASK +{ + vif0.tag.size = 1; +} + +static void Vif0CMDSTRowCol() // STROW / STCOL +{ + vif0.tag.addr = 0; + vif0.tag.size = 4; +} + +static void Vif0CMDMPGTransfer() // MPG +{ + int vifNum; + vif0FLUSH(); + vifNum = (u8)(vif0Regs->code >> 16); + if (vifNum == 0) vifNum = 256; + vif0.tag.addr = (u16)((vif0Regs->code) << 3) & 0xfff; + vif0.tag.size = vifNum * 2; +} + +static void Vif0CMDNull() // invalid opcode +{ + // if ME1, then force the vif to interrupt + if (!(vif0Regs->err.ME1)) //Ignore vifcode and tag mismatch error + { + Console.WriteLn("UNKNOWN VifCmd: %x", vif0.cmd); + vif0Regs->stat.ER1 = true; + vif0.irq++; + } + vif0.cmd &= ~0x7f; +} + + +//------------------------------------------------------------------ +// Vif0 Data Transfer / Vif0 CMD Tables +//------------------------------------------------------------------ + +int (__fastcall *Vif0TransTLB[128])(u32 *data) = +{ + Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x7*/ + Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0xF*/ + Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x17*/ + Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x1F*/ + Vif0TransSTMask , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x27*/ + Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x2F*/ + Vif0TransSTRow , Vif0TransSTCol , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x37*/ + Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x3F*/ + Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x47*/ + Vif0TransNull , Vif0TransNull , Vif0TransMPG , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x4F*/ + Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x57*/ + Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x5F*/ + Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransNull , /*0x67*/ + Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , /*0x6F*/ + Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransNull , /*0x77*/ + Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransNull , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack /*0x7F*/ +}; + +void (*Vif0CMDTLB[75])() = +{ + Vif0CMDNop , Vif0CMDSTCycl , Vif0CMDNull , Vif0CMDNull , Vif0CMDITop , Vif0CMDSTMod , Vif0CMDNull, Vif0CMDMark , /*0x7*/ + Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0xF*/ + Vif0CMDFlushE , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull, Vif0CMDMSCALF, Vif0CMDMSCALF, Vif0CMDNull , Vif0CMDMSCNT, /*0x17*/ + Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x1F*/ + Vif0CMDSTMask , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x27*/ + Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x2F*/ + Vif0CMDSTRowCol, Vif0CMDSTRowCol, Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x37*/ + Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x3F*/ + Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x47*/ + Vif0CMDNull , Vif0CMDNull , Vif0CMDMPGTransfer +}; diff --git a/pcsx2/Vif0Dma.cpp b/pcsx2/Vif0_Dma.cpp similarity index 54% rename from pcsx2/Vif0Dma.cpp rename to pcsx2/Vif0_Dma.cpp index 6f3d882412..eb1b701df9 100644 --- a/pcsx2/Vif0Dma.cpp +++ b/pcsx2/Vif0_Dma.cpp @@ -1,746 +1,446 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2009 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - - -#include "PrecompiledHeader.h" -#include "Common.h" -#include "VifDma.h" -#include "VUmicro.h" -#include "newVif.h" - -extern int (__fastcall *Vif0TransTLB[128])(u32 *data); -extern void (*Vif0CMDTLB[75])(); - -vifStruct vif0; - -__forceinline void vif0FLUSH() -{ - int _cycles = VU0.cycle; - - // fixme: this code should call _vu0WaitMicro instead? I'm not sure if - // it's purposefully ignoring ee cycles or not (see below for more) - - vu0Finish(); - g_vifCycles += (VU0.cycle - _cycles) * BIAS; -} - -void vif0Init() -{ - initNewVif(0); -} - -static __forceinline void vif0UNPACK(u32 *data) -{ - int vifNum; - - if ((vif0Regs->cycle.wl == 0) && (vif0Regs->cycle.wl < vif0Regs->cycle.cl)) - { - Console.WriteLn("Vif0 CL %d, WL %d", vif0Regs->cycle.cl, vif0Regs->cycle.wl); - vif0.cmd &= ~0x7f; - return; - } - - vif0FLUSH(); - - vif0.tag.addr = (vif0Regs->code & 0xff) << 4; - vif0.usn = (vif0Regs->code >> 14) & 0x1; - vifNum = (vif0Regs->code >> 16) & 0xff; - if (vifNum == 0) vifNum = 256; - vif0Regs->num = vifNum; - - if (vif0Regs->cycle.wl <= vif0Regs->cycle.cl) - { - vif0.tag.size = ((vifNum * VIFfuncTable[ vif0.cmd & 0xf ].gsize) + 3) >> 2; - } - else - { - int n = vif0Regs->cycle.cl * (vifNum / vif0Regs->cycle.wl) + - _limit(vifNum % vif0Regs->cycle.wl, vif0Regs->cycle.cl); - - vif0.tag.size = ((n * VIFfuncTable[ vif0.cmd & 0xf ].gsize) + 3) >> 2; - } - - vif0.cl = 0; - vif0.tag.cmd = vif0.cmd; - vif0Regs->offset = 0; -} - -static __forceinline void vif0mpgTransfer(u32 addr, u32 *data, int size) -{ - /* Console.WriteLn("vif0mpgTransfer addr=%x; size=%x", addr, size); - { - FILE *f = fopen("vu1.raw", "wb"); - fwrite(data, 1, size*4, f); - fclose(f); - }*/ - if (memcmp(VU0.Micro + addr, data, size << 2)) - { - CpuVU0->Clear(addr, size << 2); // Clear before writing! :/ (cottonvibes) - memcpy_fast(VU0.Micro + addr, data, size << 2); - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Vif0 Data Transfer Commands -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -static int __fastcall Vif0TransNull(u32 *data) // Shouldnt go here -{ - Console.WriteLn("VIF0 Shouldn't go here CMD = %x", vif0Regs->code); - vif0.cmd = 0; - return 0; -} - -static int __fastcall Vif0TransSTMask(u32 *data) // STMASK -{ - vif0Regs->mask = data[0]; - VIF_LOG("STMASK == %x", vif0Regs->mask); - - vif0.tag.size = 0; - vif0.cmd = 0; - return 1; -} - -static int __fastcall Vif0TransSTRow(u32 *data) // STROW -{ - int ret; - - u32* pmem = &vif0Regs->r0 + (vif0.tag.addr << 2); - u32* pmem2 = g_vifmask.Row0 + vif0.tag.addr; - pxAssume(vif0.tag.addr < 4); - ret = min(4 - vif0.tag.addr, vif0.vifpacketsize); - pxAssume(ret > 0); - - switch (ret) - { - case 4: - pmem[12] = data[3]; - pmem2[3] = data[3]; - case 3: - pmem[8] = data[2]; - pmem2[2] = data[2]; - case 2: - pmem[4] = data[1]; - pmem2[1] = data[1]; - case 1: - pmem[0] = data[0]; - pmem2[0] = data[0]; - break; - - jNO_DEFAULT - } - - vif0.tag.addr += ret; - vif0.tag.size -= ret; - if (vif0.tag.size == 0) vif0.cmd = 0; - - return ret; -} - -static int __fastcall Vif0TransSTCol(u32 *data) // STCOL -{ - int ret; - - u32* pmem = &vif0Regs->c0 + (vif0.tag.addr << 2); - u32* pmem2 = g_vifmask.Col0 + vif0.tag.addr; - ret = min(4 - vif0.tag.addr, vif0.vifpacketsize); - - switch (ret) - { - case 4: - pmem[12] = data[3]; - pmem2[3] = data[3]; - case 3: - pmem[8] = data[2]; - pmem2[2] = data[2]; - case 2: - pmem[4] = data[1]; - pmem2[1] = data[1]; - case 1: - pmem[0] = data[0]; - pmem2[0] = data[0]; - break; - - jNO_DEFAULT - } - - vif0.tag.addr += ret; - vif0.tag.size -= ret; - if (vif0.tag.size == 0) vif0.cmd = 0; - return ret; -} - -static int __fastcall Vif0TransMPG(u32 *data) // MPG -{ - if (vif0.vifpacketsize < vif0.tag.size) - { - if((vif0.tag.addr + vif0.vifpacketsize) > 0x1000) DevCon.Warning("Vif0 MPG Split Overflow"); - - vif0mpgTransfer(vif0.tag.addr, data, vif0.vifpacketsize); - vif0.tag.addr += vif0.vifpacketsize << 2; - vif0.tag.size -= vif0.vifpacketsize; - - return vif0.vifpacketsize; - } - else - { - int ret; - - if((vif0.tag.addr + vif0.tag.size) > 0x1000) DevCon.Warning("Vif0 MPG Overflow"); - - vif0mpgTransfer(vif0.tag.addr, data, vif0.tag.size); - ret = vif0.tag.size; - vif0.tag.size = 0; - vif0.cmd = 0; - - return ret; - } -} - -static int __fastcall Vif0TransUnpack(u32 *data) // UNPACK -{ - return nVifUnpack(0, (u8*)data); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Vif0 CMD Base Commands -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -static void Vif0CMDNop() // NOP -{ - vif0.cmd &= ~0x7f; -} - -static void Vif0CMDSTCycl() // STCYCL -{ - vif0Regs->cycle.cl = (u8)vif0Regs->code; - vif0Regs->cycle.wl = (u8)(vif0Regs->code >> 8); - vif0.cmd &= ~0x7f; -} - -static void Vif0CMDITop() // ITOP -{ - vif0Regs->itops = vif0Regs->code & 0x3ff; - vif0.cmd &= ~0x7f; -} - -static void Vif0CMDSTMod() // STMOD -{ - vif0Regs->mode = vif0Regs->code & 0x3; - vif0.cmd &= ~0x7f; -} - -static void Vif0CMDMark() // MARK -{ - vif0Regs->mark = (u16)vif0Regs->code; - vif0Regs->stat.MRK = true; - vif0.cmd &= ~0x7f; -} - -static void Vif0CMDFlushE() // FLUSHE -{ - vif0FLUSH(); - vif0.cmd &= ~0x7f; -} - -static void Vif0CMDMSCALF() //MSCAL/F -{ - vuExecMicro<0>((u16)(vif0Regs->code) << 3); - vif0.cmd &= ~0x7f; -} - -static void Vif0CMDMSCNT() // MSCNT -{ - vuExecMicro<0>(-1); - vif0.cmd &= ~0x7f; -} - -static void Vif0CMDSTMask() // STMASK -{ - vif0.tag.size = 1; -} - -static void Vif0CMDSTRowCol() // STROW / STCOL -{ - vif0.tag.addr = 0; - vif0.tag.size = 4; -} - -static void Vif0CMDMPGTransfer() // MPG -{ - int vifNum; - vif0FLUSH(); - vifNum = (u8)(vif0Regs->code >> 16); - if (vifNum == 0) vifNum = 256; - vif0.tag.addr = (u16)((vif0Regs->code) << 3) & 0xfff; - vif0.tag.size = vifNum * 2; -} - -static void Vif0CMDNull() // invalid opcode -{ - // if ME1, then force the vif to interrupt - if (!(vif0Regs->err.ME1)) //Ignore vifcode and tag mismatch error - { - Console.WriteLn("UNKNOWN VifCmd: %x", vif0.cmd); - vif0Regs->stat.ER1 = true; - vif0.irq++; - } - vif0.cmd &= ~0x7f; -} - -bool VIF0transfer(u32 *data, int size, bool istag) -{ - int ret; - int transferred = vif0.vifstalled ? vif0.irqoffset : 0; // irqoffset necessary to add up the right qws, or else will spin (spiderman) - VIF_LOG("VIF0transfer: size %x (vif0.cmd %x)", size, vif0.cmd); - - vif0.stallontag = false; - vif0.vifstalled = false; - vif0.vifpacketsize = size; - - while (vif0.vifpacketsize > 0) - { - if (vif0.cmd) - { - vif0Regs->stat.VPS = VPS_TRANSFERRING; //Decompression has started - - ret = Vif0TransTLB[(vif0.cmd & 0x7f)](data); - data += ret; - vif0.vifpacketsize -= ret; - if (vif0.cmd == 0) vif0Regs->stat.VPS = VPS_IDLE; //We are once again waiting for a new vifcode as the command has cleared - continue; - } - - if (vif0.tag.size != 0) Console.WriteLn("no vif0 cmd but tag size is left last cmd read %x", vif0Regs->code); - - // if interrupt and new cmd is NOT MARK - if (vif0.irq) break; - - vif0.cmd = (data[0] >> 24); - vif0Regs->code = data[0]; - - vif0Regs->stat.VPS |= VPS_DECODING; //We need to set these (Onimusha needs it) - - if ((vif0.cmd & 0x60) == 0x60) - { - vif0UNPACK(data); - } - else - { - VIF_LOG("VIFtransfer: cmd %x, num %x, imm %x, size %x", vif0.cmd, (data[0] >> 16) & 0xff, data[0] & 0xffff, size); - - if ((vif0.cmd & 0x7f) > 0x4A) - { - if (!(vif0Regs->err.ME1)) //Ignore vifcode and tag mismatch error - { - Console.WriteLn("UNKNOWN VifCmd: %x", vif0.cmd); - vif0Regs->stat.ER1 = true; - vif0.irq++; - } - vif0.cmd = 0; - } - else - { - Vif0CMDTLB[(vif0.cmd & 0x7f)](); - } - } - ++data; - --vif0.vifpacketsize; - - if ((vif0.cmd & 0x80)) - { - vif0.cmd &= 0x7f; - - if (!(vif0Regs->err.MII)) //i bit on vifcode and not masked by VIF0_ERR - { - VIF_LOG("Interrupt on VIFcmd: %x (INTC_MASK = %x)", vif0.cmd, psHu32(INTC_MASK)); - - ++vif0.irq; - - if (istag && vif0.tag.size <= vif0.vifpacketsize) vif0.stallontag = true; - - if (vif0.tag.size == 0) break; - } - } - } //End of Transfer loop - - transferred += size - vif0.vifpacketsize; - g_vifCycles += (transferred >> 2) * BIAS; /* guessing */ - // use tag.size because some game doesn't like .cmd - - if (vif0.irq && (vif0.tag.size == 0)) - { - vif0.vifstalled = true; - - if (((vif0Regs->code >> 24) & 0x7f) != 0x7) vif0Regs->stat.VIS = true; - //else Console.WriteLn("VIF0 IRQ on MARK"); - - // spiderman doesn't break on qw boundaries - vif0.irqoffset = transferred % 4; // cannot lose the offset - - if (!istag) - { - transferred = transferred >> 2; - vif0ch->madr += (transferred << 4); - vif0ch->qwc -= transferred; - } - //else Console.WriteLn("Stall on vif0, FromSPR = %x, Vif0MADR = %x Sif0MADR = %x STADR = %x", psHu32(0x1000d010), vif0ch->madr, psHu32(0x1000c010), psHu32(DMAC_STADR)); - return false; - } - - vif0Regs->stat.VPS = VPS_IDLE; //Vif goes idle as the stall happened between commands; - if (vif0.cmd) vif0Regs->stat.VPS |= VPS_WAITING; //Otherwise we wait for the data - - if (!istag) - { - transferred = transferred >> 2; - vif0ch->madr += (transferred << 4); - vif0ch->qwc -= transferred; - } - - return true; -} - -bool _VIF0chain() -{ - u32 *pMem; - - if ((vif0ch->qwc == 0) && !vif0.vifstalled) return true; - - pMem = (u32*)dmaGetAddr(vif0ch->madr); - if (pMem == NULL) - { - vif0.cmd = 0; - vif0.tag.size = 0; - vif0ch->qwc = 0; - return true; - } - - if (vif0.vifstalled) - return VIF0transfer(pMem + vif0.irqoffset, vif0ch->qwc * 4 - vif0.irqoffset, false); - else - return VIF0transfer(pMem, vif0ch->qwc * 4, false); -} - -bool _chainVIF0() -{ - 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) - { - 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)) return false; //IRQ set by VIFTransfer - } - - 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() -{ - 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)) - { - 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; - vif0ch->chcr.STR = false; - return; - } - - if (vif0ch->qwc > 0 || vif0.irqoffset > 0) - { - if (vif0.stallontag) - _chainVIF0(); - else - _VIF0chain(); - - CPU_INT(0, /*g_vifCycles*/ VifCycleVoodoo); - return; - } - } - - if (!vif0ch->chcr.STR) Console.WriteLn("Vif0 running when CHCR = %x", vif0ch->chcr._u32); - - if ((vif0ch->chcr.MOD == CHAIN_MODE) && (!vif0.done) && (!vif0.vifstalled)) - { - - if (!(dmacRegs->ctrl.DMAE)) - { - Console.WriteLn("vif0 dma masked"); - return; - } - - if (vif0ch->qwc > 0) - _VIF0chain(); - else - _chainVIF0(); - - CPU_INT(0, /*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); - - vif0ch->chcr.STR = false; - hwDmacIrq(DMAC_VIF0); - vif0Regs->stat.FQC = 0; -} - -// Vif0 Data Transfer Table -int (__fastcall *Vif0TransTLB[128])(u32 *data) = -{ - Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x7*/ - Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0xF*/ - Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x17*/ - Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x1F*/ - Vif0TransSTMask , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x27*/ - Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x2F*/ - Vif0TransSTRow , Vif0TransSTCol , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x37*/ - Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x3F*/ - Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x47*/ - Vif0TransNull , Vif0TransNull , Vif0TransMPG , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x4F*/ - Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x57*/ - Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x5F*/ - Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransNull , /*0x67*/ - Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , /*0x6F*/ - Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransNull , /*0x77*/ - Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransNull , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack /*0x7F*/ -}; - -// Vif0 CMD Table -void (*Vif0CMDTLB[75])() = -{ - Vif0CMDNop , Vif0CMDSTCycl , Vif0CMDNull , Vif0CMDNull , Vif0CMDITop , Vif0CMDSTMod , Vif0CMDNull, Vif0CMDMark , /*0x7*/ - Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0xF*/ - Vif0CMDFlushE , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull, Vif0CMDMSCALF, Vif0CMDMSCALF, Vif0CMDNull , Vif0CMDMSCNT, /*0x17*/ - Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x1F*/ - Vif0CMDSTMask , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x27*/ - Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x2F*/ - Vif0CMDSTRowCol, Vif0CMDSTRowCol, Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x37*/ - Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x3F*/ - Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x47*/ - Vif0CMDNull , Vif0CMDNull , Vif0CMDMPGTransfer -}; - -void dmaVIF0() -{ - VIF_LOG("dmaVIF0 chcr = %lx, madr = %lx, qwc = %lx\n" - " tadr = %lx, asr0 = %lx, asr1 = %lx\n", - vif0ch->chcr._u32, vif0ch->madr, vif0ch->qwc, - vif0ch->tadr, vif0ch->asr0, vif0ch->asr1); - - g_vifCycles = 0; - - vif0Regs->stat.FQC = 0x8; // FQC=8 - - if (!(vif0ch->chcr.MOD & 0x1) || 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(0, /*g_vifCycles*/ VifCycleVoodoo); - return; - } - - // Chain Mode - vif0.done = false; - CPU_INT(0, 0); -} - -void vif0Write32(u32 mem, u32 value) -{ - switch (mem) - { - case VIF0_MARK: - VIF_LOG("VIF0_MARK write32 0x%8.8x", value); - - /* Clear mark flag in VIF0_STAT and set mark with 'value' */ - vif0Regs->stat.MRK = false; - vif0Regs->mark = value; - break; - - case VIF0_FBRST: - VIF_LOG("VIF0_FBRST write32 0x%8.8x", value); - - if (value & 0x1) // Reset Vif. - { - //Console.WriteLn("Vif0 Reset %x", vif0Regs->stat._u32); - - memzero(vif0); - vif0ch->qwc = 0; //? - cpuRegs.interrupt &= ~1; //Stop all vif0 DMA's - psHu64(VIF0_FIFO) = 0; - psHu64(VIF0_FIFO + 8) = 0; - vif0.done = true; - vif0Regs->err.reset(); - vif0Regs->stat.clear_flags(VIF0_STAT_FQC | VIF0_STAT_INT | VIF0_STAT_VSS | VIF0_STAT_VIS | VIF0_STAT_VFS | VIF0_STAT_VPS); // FQC=0 - } - - if (value & 0x2) // Forcebreak Vif, - { - /* I guess we should stop the VIF dma here, but not 100% sure (linuz) */ - cpuRegs.interrupt &= ~1; //Stop all vif0 DMA's - vif0Regs->stat.VFS = true; - vif0Regs->stat.VPS = VPS_IDLE; - vif0.vifstalled = true; - Console.WriteLn("vif0 force break"); - } - - if (value & 0x4) // Stop Vif. - { - // Not completely sure about this, can't remember what game, used this, but 'draining' the VIF helped it, instead of - // just stoppin the VIF (linuz). - vif0Regs->stat.VSS = true; - vif0Regs->stat.VPS = VPS_IDLE; - vif0.vifstalled = true; - } - - if (value & 0x8) // Cancel Vif Stall. - { - bool cancel = false; - - /* Cancel stall, first check if there is a stall to cancel, and then clear VIF0_STAT VSS|VFS|VIS|INT|ER0|ER1 bits */ - if (vif0Regs->stat.test(VIF0_STAT_VSS | VIF0_STAT_VIS | VIF0_STAT_VFS)) - cancel = true; - - vif0Regs->stat.clear_flags(VIF0_STAT_VSS | VIF0_STAT_VFS | VIF0_STAT_VIS | - VIF0_STAT_INT | VIF0_STAT_ER0 | VIF0_STAT_ER1); - if (cancel) - { - if (vif0.vifstalled) - { - g_vifCycles = 0; - - // loop necessary for spiderman - if (vif0.stallontag) - _chainVIF0(); - else - _VIF0chain(); - - vif0ch->chcr.STR = true; - CPU_INT(0, g_vifCycles); // Gets the timing right - Flatout - } - } - } - break; - - case VIF0_ERR: - // ERR - VIF_LOG("VIF0_ERR write32 0x%8.8x", value); - - /* Set VIF0_ERR with 'value' */ - vif0Regs->err.write(value); - break; - - case VIF0_R0: - case VIF0_R1: - case VIF0_R2: - case VIF0_R3: - pxAssume((mem&0xf) == 0); - g_vifmask.Row0[(mem>>4) & 3] = value; - break; - - case VIF0_C0: - case VIF0_C1: - case VIF0_C2: - case VIF0_C3: - pxAssume((mem&0xf) == 0); - g_vifmask.Col0[(mem>>4) & 3] = value; - break; - - default: - Console.WriteLn("Unknown Vif0 write to %x", mem); - psHu32(mem) = value; - break; - } - /* Other registers are read-only so do nothing for them */ -} - -void vif0Reset() -{ - /* Reset the whole VIF, meaning the internal pcsx2 vars and all the registers */ - memzero(vif0); - memzero(*vif0Regs); - - psHu64(VIF0_FIFO) = 0; - psHu64(VIF0_FIFO + 8) = 0; - - vif0Regs->stat.VPS = VPS_IDLE; - vif0Regs->stat.FQC = 0; - - vif0.done = true; - - resetNewVif(0); -} - -void SaveStateBase::vif0Freeze() -{ - static u32 g_vif0Masks[64]; // Dummy Var for saved state compatibility - static u32 g_vif0HasMask3[4]; // Dummy Var for saved state compatibility - FreezeTag("VIFdma"); - - // Dunno if this one is needed, but whatever, it's small. :) - Freeze(g_vifCycles); - - // mask settings for VIF0 and VIF1 - Freeze(g_vifmask); - - Freeze(vif0); - Freeze(g_vif0HasMask3); // Not Used Anymore - Freeze(g_vif0Masks); // Not Used Anymore -} +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2009 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#include "PrecompiledHeader.h" +#include "Common.h" +#include "Vif_Dma.h" +#include "VUmicro.h" +#include "newVif.h" + +extern int (__fastcall *Vif0TransTLB[128])(u32 *data); +extern void (*Vif0CMDTLB[75])(); +vifStruct vif0; + +__forceinline void vif0FLUSH() +{ + int _cycles = VU0.cycle; + + // fixme: this code should call _vu0WaitMicro instead? I'm not sure if + // it's purposefully ignoring ee cycles or not (see below for more) + + vu0Finish(); + g_vifCycles += (VU0.cycle - _cycles) * BIAS; +} + +static __forceinline void vif0UNPACK(u32 *data) +{ + int vifNum; + + if ((vif0Regs->cycle.wl == 0) && (vif0Regs->cycle.wl < vif0Regs->cycle.cl)) + { + Console.WriteLn("Vif0 CL %d, WL %d", vif0Regs->cycle.cl, vif0Regs->cycle.wl); + vif0.cmd &= ~0x7f; + return; + } + + vif0FLUSH(); + + vif0.tag.addr = (vif0Regs->code & 0xff) << 4; + vif0.usn = (vif0Regs->code >> 14) & 0x1; + vifNum = (vif0Regs->code >> 16) & 0xff; + if (vifNum == 0) vifNum = 256; + vif0Regs->num = vifNum; + + if (vif0Regs->cycle.wl <= vif0Regs->cycle.cl) + { + vif0.tag.size = ((vifNum * VIFfuncTable[ vif0.cmd & 0xf ].gsize) + 3) >> 2; + } + else + { + int n = vif0Regs->cycle.cl * (vifNum / vif0Regs->cycle.wl) + + _limit(vifNum % vif0Regs->cycle.wl, vif0Regs->cycle.cl); + + vif0.tag.size = ((n * VIFfuncTable[ vif0.cmd & 0xf ].gsize) + 3) >> 2; + } + + vif0.cl = 0; + vif0.tag.cmd = vif0.cmd; + vif0Regs->offset = 0; +} + +bool VIF0transfer(u32 *data, int size, bool istag) +{ + int ret; + int transferred = vif0.vifstalled ? vif0.irqoffset : 0; // irqoffset necessary to add up the right qws, or else will spin (spiderman) + VIF_LOG("VIF0transfer: size %x (vif0.cmd %x)", size, vif0.cmd); + + vif0.stallontag = false; + vif0.vifstalled = false; + vif0.vifpacketsize = size; + + while (vif0.vifpacketsize > 0) + { + if (vif0.cmd) + { + vif0Regs->stat.VPS = VPS_TRANSFERRING; //Decompression has started + + ret = Vif0TransTLB[(vif0.cmd & 0x7f)](data); + data += ret; + vif0.vifpacketsize -= ret; + if (vif0.cmd == 0) vif0Regs->stat.VPS = VPS_IDLE; //We are once again waiting for a new vifcode as the command has cleared + continue; + } + + if (vif0.tag.size != 0) Console.WriteLn("no vif0 cmd but tag size is left last cmd read %x", vif0Regs->code); + + // if interrupt and new cmd is NOT MARK + if (vif0.irq) break; + + vif0.cmd = (data[0] >> 24); + vif0Regs->code = data[0]; + + vif0Regs->stat.VPS |= VPS_DECODING; //We need to set these (Onimusha needs it) + + if ((vif0.cmd & 0x60) == 0x60) + { + vif0UNPACK(data); + } + else + { + VIF_LOG("VIFtransfer: cmd %x, num %x, imm %x, size %x", vif0.cmd, (data[0] >> 16) & 0xff, data[0] & 0xffff, size); + + if ((vif0.cmd & 0x7f) > 0x4A) + { + if (!(vif0Regs->err.ME1)) //Ignore vifcode and tag mismatch error + { + Console.WriteLn("UNKNOWN VifCmd: %x", vif0.cmd); + vif0Regs->stat.ER1 = true; + vif0.irq++; + } + vif0.cmd = 0; + } + else + { + Vif0CMDTLB[(vif0.cmd & 0x7f)](); + } + } + ++data; + --vif0.vifpacketsize; + + if ((vif0.cmd & 0x80)) + { + vif0.cmd &= 0x7f; + + if (!(vif0Regs->err.MII)) //i bit on vifcode and not masked by VIF0_ERR + { + VIF_LOG("Interrupt on VIFcmd: %x (INTC_MASK = %x)", vif0.cmd, psHu32(INTC_MASK)); + + ++vif0.irq; + + if (istag && vif0.tag.size <= vif0.vifpacketsize) vif0.stallontag = true; + + if (vif0.tag.size == 0) break; + } + } + } //End of Transfer loop + + transferred += size - vif0.vifpacketsize; + g_vifCycles += (transferred >> 2) * BIAS; /* guessing */ + // use tag.size because some game doesn't like .cmd + + if (vif0.irq && (vif0.tag.size == 0)) + { + vif0.vifstalled = true; + + if (((vif0Regs->code >> 24) & 0x7f) != 0x7) vif0Regs->stat.VIS = true; + //else Console.WriteLn("VIF0 IRQ on MARK"); + + // spiderman doesn't break on qw boundaries + vif0.irqoffset = transferred % 4; // cannot lose the offset + + if (!istag) + { + transferred = transferred >> 2; + vif0ch->madr += (transferred << 4); + vif0ch->qwc -= transferred; + } + //else Console.WriteLn("Stall on vif0, FromSPR = %x, Vif0MADR = %x Sif0MADR = %x STADR = %x", psHu32(0x1000d010), vif0ch->madr, psHu32(0x1000c010), psHu32(DMAC_STADR)); + return false; + } + + vif0Regs->stat.VPS = VPS_IDLE; //Vif goes idle as the stall happened between commands; + if (vif0.cmd) vif0Regs->stat.VPS |= VPS_WAITING; //Otherwise we wait for the data + + if (!istag) + { + transferred = transferred >> 2; + vif0ch->madr += (transferred << 4); + vif0ch->qwc -= transferred; + } + + return true; +} + +bool _VIF0chain() +{ + u32 *pMem; + + if ((vif0ch->qwc == 0) && !vif0.vifstalled) return true; + + pMem = (u32*)dmaGetAddr(vif0ch->madr); + if (pMem == NULL) + { + vif0.cmd = 0; + vif0.tag.size = 0; + vif0ch->qwc = 0; + return true; + } + + if (vif0.vifstalled) + return VIF0transfer(pMem + vif0.irqoffset, vif0ch->qwc * 4 - vif0.irqoffset, false); + else + return VIF0transfer(pMem, vif0ch->qwc * 4, false); +} + +bool _chainVIF0() +{ + 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) + { + 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)) return false; //IRQ set by VIFTransfer + } + + 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() +{ + 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)) + { + 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; + vif0ch->chcr.STR = false; + return; + } + + if (vif0ch->qwc > 0 || vif0.irqoffset > 0) + { + if (vif0.stallontag) + _chainVIF0(); + else + _VIF0chain(); + + CPU_INT(0, /*g_vifCycles*/ VifCycleVoodoo); + return; + } + } + + if (!vif0ch->chcr.STR) Console.WriteLn("Vif0 running when CHCR = %x", vif0ch->chcr._u32); + + if ((vif0ch->chcr.MOD == CHAIN_MODE) && (!vif0.done) && (!vif0.vifstalled)) + { + + if (!(dmacRegs->ctrl.DMAE)) + { + Console.WriteLn("vif0 dma masked"); + return; + } + + if (vif0ch->qwc > 0) + _VIF0chain(); + else + _chainVIF0(); + + CPU_INT(0, /*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); + + vif0ch->chcr.STR = false; + hwDmacIrq(DMAC_VIF0); + vif0Regs->stat.FQC = 0; +} + +void dmaVIF0() +{ + VIF_LOG("dmaVIF0 chcr = %lx, madr = %lx, qwc = %lx\n" + " tadr = %lx, asr0 = %lx, asr1 = %lx\n", + vif0ch->chcr._u32, vif0ch->madr, vif0ch->qwc, + vif0ch->tadr, vif0ch->asr0, vif0ch->asr1); + + g_vifCycles = 0; + + vif0Regs->stat.FQC = 0x8; // FQC=8 + + if (!(vif0ch->chcr.MOD & 0x1) || 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(0, /*g_vifCycles*/ VifCycleVoodoo); + return; + } + + // Chain Mode + vif0.done = false; + CPU_INT(0, 0); +} + +void vif0Write32(u32 mem, u32 value) +{ + switch (mem) + { + case VIF0_MARK: + VIF_LOG("VIF0_MARK write32 0x%8.8x", value); + + /* Clear mark flag in VIF0_STAT and set mark with 'value' */ + vif0Regs->stat.MRK = false; + vif0Regs->mark = value; + break; + + case VIF0_FBRST: + VIF_LOG("VIF0_FBRST write32 0x%8.8x", value); + + if (value & 0x1) // Reset Vif. + { + //Console.WriteLn("Vif0 Reset %x", vif0Regs->stat._u32); + + memzero(vif0); + vif0ch->qwc = 0; //? + cpuRegs.interrupt &= ~1; //Stop all vif0 DMA's + psHu64(VIF0_FIFO) = 0; + psHu64(VIF0_FIFO + 8) = 0; + vif0.done = true; + vif0Regs->err.reset(); + vif0Regs->stat.clear_flags(VIF0_STAT_FQC | VIF0_STAT_INT | VIF0_STAT_VSS | VIF0_STAT_VIS | VIF0_STAT_VFS | VIF0_STAT_VPS); // FQC=0 + } + + if (value & 0x2) // Forcebreak Vif, + { + /* I guess we should stop the VIF dma here, but not 100% sure (linuz) */ + cpuRegs.interrupt &= ~1; //Stop all vif0 DMA's + vif0Regs->stat.VFS = true; + vif0Regs->stat.VPS = VPS_IDLE; + vif0.vifstalled = true; + Console.WriteLn("vif0 force break"); + } + + if (value & 0x4) // Stop Vif. + { + // Not completely sure about this, can't remember what game, used this, but 'draining' the VIF helped it, instead of + // just stoppin the VIF (linuz). + vif0Regs->stat.VSS = true; + vif0Regs->stat.VPS = VPS_IDLE; + vif0.vifstalled = true; + } + + if (value & 0x8) // Cancel Vif Stall. + { + bool cancel = false; + + /* Cancel stall, first check if there is a stall to cancel, and then clear VIF0_STAT VSS|VFS|VIS|INT|ER0|ER1 bits */ + if (vif0Regs->stat.test(VIF0_STAT_VSS | VIF0_STAT_VIS | VIF0_STAT_VFS)) + cancel = true; + + vif0Regs->stat.clear_flags(VIF0_STAT_VSS | VIF0_STAT_VFS | VIF0_STAT_VIS | + VIF0_STAT_INT | VIF0_STAT_ER0 | VIF0_STAT_ER1); + if (cancel) + { + if (vif0.vifstalled) + { + g_vifCycles = 0; + + // loop necessary for spiderman + if (vif0.stallontag) + _chainVIF0(); + else + _VIF0chain(); + + vif0ch->chcr.STR = true; + CPU_INT(0, g_vifCycles); // Gets the timing right - Flatout + } + } + } + break; + + case VIF0_ERR: + // ERR + VIF_LOG("VIF0_ERR write32 0x%8.8x", value); + + /* Set VIF0_ERR with 'value' */ + vif0Regs->err.write(value); + break; + + case VIF0_R0: + case VIF0_R1: + case VIF0_R2: + case VIF0_R3: + pxAssume((mem&0xf) == 0); + g_vifmask.Row0[(mem>>4) & 3] = value; + break; + + case VIF0_C0: + case VIF0_C1: + case VIF0_C2: + case VIF0_C3: + pxAssume((mem&0xf) == 0); + g_vifmask.Col0[(mem>>4) & 3] = value; + break; + + default: + Console.WriteLn("Unknown Vif0 write to %x", mem); + psHu32(mem) = value; + break; + } + /* Other registers are read-only so do nothing for them */ +} diff --git a/pcsx2/Vif1_Commands.cpp b/pcsx2/Vif1_Commands.cpp new file mode 100644 index 0000000000..157b87c08e --- /dev/null +++ b/pcsx2/Vif1_Commands.cpp @@ -0,0 +1,425 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2009 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#include "PrecompiledHeader.h" +#include "Common.h" +#include "Vif_Dma.h" +#include "GS.h" +#include "Gif.h" +#include "VUmicro.h" + +//------------------------------------------------------------------ +// Vif1 Data Transfer Commands +//------------------------------------------------------------------ + +static int __fastcall Vif1TransNull(u32 *data) // Shouldnt go here +{ + Console.WriteLn("VIF1 Shouldn't go here CMD = %x", vif1Regs->code); + vif1.cmd = 0; + return 0; +} + +static int __fastcall Vif1TransSTMask(u32 *data) // STMASK +{ + vif1Regs->mask = data[0]; + VIF_LOG("STMASK == %x", vif1Regs->mask); + + vif1.tag.size = 0; + vif1.cmd = 0; + return 1; +} + +static int __fastcall Vif1TransSTRow(u32 *data) // STROW +{ + int ret; + + u32* pmem = &vif1Regs->r0 + (vif1.tag.addr << 2); + u32* pmem2 = g_vifmask.Row1 + vif1.tag.addr; + pxAssume(vif1.tag.addr < 4); + ret = min(4 - vif1.tag.addr, vif1.vifpacketsize); + pxAssume(ret > 0); + + switch (ret) + { + case 4: + pmem[12] = data[3]; + pmem2[3] = data[3]; + case 3: + pmem[8] = data[2]; + pmem2[2] = data[2]; + case 2: + pmem[4] = data[1]; + pmem2[1] = data[1]; + case 1: + pmem[0] = data[0]; + pmem2[0] = data[0]; + break; + jNO_DEFAULT; + } + + vif1.tag.addr += ret; + vif1.tag.size -= ret; + if (vif1.tag.size == 0) vif1.cmd = 0; + + return ret; +} + +static int __fastcall Vif1TransSTCol(u32 *data) +{ + int ret; + + u32* pmem = &vif1Regs->c0 + (vif1.tag.addr << 2); + u32* pmem2 = g_vifmask.Col1 + vif1.tag.addr; + ret = min(4 - vif1.tag.addr, vif1.vifpacketsize); + switch (ret) + { + case 4: + pmem[12] = data[3]; + pmem2[3] = data[3]; + case 3: + pmem[8] = data[2]; + pmem2[2] = data[2]; + case 2: + pmem[4] = data[1]; + pmem2[1] = data[1]; + case 1: + pmem[0] = data[0]; + pmem2[0] = data[0]; + break; + jNO_DEFAULT; + } + vif1.tag.addr += ret; + vif1.tag.size -= ret; + if (vif1.tag.size == 0) vif1.cmd = 0; + return ret; +} + +static __forceinline void vif1mpgTransfer(u32 addr, u32 *data, int size) +{ + pxAssume(VU1.Micro > 0); + if (memcmp(VU1.Micro + addr, data, size << 2)) + { + CpuVU1->Clear(addr, size << 2); // Clear before writing! :/ + memcpy_fast(VU1.Micro + addr, data, size << 2); + } +} + +static int __fastcall Vif1TransMPG(u32 *data) +{ + if (vif1.vifpacketsize < vif1.tag.size) + { + if((vif1.tag.addr + vif1.vifpacketsize) > 0x4000) DevCon.Warning("Vif1 MPG Split Overflow"); + vif1mpgTransfer(vif1.tag.addr, data, vif1.vifpacketsize); + vif1.tag.addr += vif1.vifpacketsize << 2; + vif1.tag.size -= vif1.vifpacketsize; + return vif1.vifpacketsize; + } + else + { + int ret; + if((vif1.tag.addr + vif1.tag.size) > 0x4000) DevCon.Warning("Vif1 MPG Overflow"); + vif1mpgTransfer(vif1.tag.addr, data, vif1.tag.size); + ret = vif1.tag.size; + vif1.tag.size = 0; + vif1.cmd = 0; + return ret; + } +} + +// Dummy GIF-TAG Packet to Guarantee Count = 1 +extern __aligned16 u32 nloop0_packet[4]; +static __aligned16 u32 splittransfer[4]; +static u32 splitptr = 0; + +static int __fastcall Vif1TransDirectHL(u32 *data) +{ + int ret = 0; + + if ((vif1.cmd & 0x7f) == 0x51) + { + if (gif->chcr.STR && (!vif1Regs->mskpath3 && (Path3progress == IMAGE_MODE))) //PATH3 is in image mode, so wait for end of transfer + { + vif1Regs->stat.VGW = true; + return 0; + } + } + + gifRegs->stat.APATH |= GIF_APATH2; + gifRegs->stat.OPH = true; + + if (splitptr > 0) //Leftover data from the last packet, filling the rest and sending to the GS + { + if ((splitptr < 4) && (vif1.vifpacketsize >= (4 - splitptr))) + { + while (splitptr < 4) + { + splittransfer[splitptr++] = (u32)data++; + ret++; + vif1.tag.size--; + } + } + + Registers::Freeze(); + // copy 16 bytes the fast way: + const u64* src = (u64*)splittransfer[0]; + GetMTGS().PrepDataPacket(GIF_PATH_2, nloop0_packet, 1); + u64* dst = (u64*)GetMTGS().GetDataPacketPtr(); + dst[0] = src[0]; + dst[1] = src[1]; + + GetMTGS().SendDataPacket(); + Registers::Thaw(); + + if (vif1.tag.size == 0) vif1.cmd = 0; + splitptr = 0; + return ret; + } + + if (vif1.vifpacketsize < vif1.tag.size) + { + if (vif1.vifpacketsize < 4 && splitptr != 4) //Not a full QW left in the buffer, saving left over data + { + ret = vif1.vifpacketsize; + while (ret > 0) + { + splittransfer[splitptr++] = (u32)data++; + vif1.tag.size--; + ret--; + } + return vif1.vifpacketsize; + } + vif1.tag.size -= vif1.vifpacketsize; + ret = vif1.vifpacketsize; + } + else + { + gifRegs->stat.clear_flags(GIF_STAT_APATH2 | GIF_STAT_OPH); + ret = vif1.tag.size; + vif1.tag.size = 0; + vif1.cmd = 0; + } + + //TODO: ret is guaranteed to be qword aligned ? + + Registers::Freeze(); + + // Round ret up, just in case it's not 128bit aligned. + const uint count = GetMTGS().PrepDataPacket(GIF_PATH_2, data, (ret + 3) >> 2); + memcpy_fast(GetMTGS().GetDataPacketPtr(), data, count << 4); + GetMTGS().SendDataPacket(); + + Registers::Thaw(); + + return ret; +} +static int __fastcall Vif1TransUnpack(u32 *data) +{ + return nVifUnpack(1, (u8*)data); +} + +//------------------------------------------------------------------ +// Vif1 CMD Base Commands +//------------------------------------------------------------------ + +static void Vif1CMDNop() // NOP +{ + vif1.cmd &= ~0x7f; +} + +static void Vif1CMDSTCycl() // STCYCL +{ + vif1Regs->cycle.cl = (u8)vif1Regs->code; + vif1Regs->cycle.wl = (u8)(vif1Regs->code >> 8); + vif1.cmd &= ~0x7f; +} + +static void Vif1CMDOffset() // OFFSET +{ + vif1Regs->ofst = vif1Regs->code & 0x3ff; + vif1Regs->stat.DBF = false; + vif1Regs->tops = vif1Regs->base; + vif1.cmd &= ~0x7f; +} + +static void Vif1CMDBase() // BASE +{ + vif1Regs->base = vif1Regs->code & 0x3ff; + vif1.cmd &= ~0x7f; +} + +static void Vif1CMDITop() // ITOP +{ + vif1Regs->itops = vif1Regs->code & 0x3ff; + vif1.cmd &= ~0x7f; +} + +static void Vif1CMDSTMod() // STMOD +{ + vif1Regs->mode = vif1Regs->code & 0x3; + vif1.cmd &= ~0x7f; +} + +u8 schedulepath3msk = 0; + +void Vif1MskPath3() // MSKPATH3 +{ + vif1Regs->mskpath3 = schedulepath3msk & 0x1; + //Console.WriteLn("VIF MSKPATH3 %x", vif1Regs->mskpath3); + + if (vif1Regs->mskpath3) + { + gifRegs->stat.M3P = true; + } + else + { + //Let the Gif know it can transfer again (making sure any vif stall isnt unset prematurely) + Path3progress = TRANSFER_MODE; + gifRegs->stat.IMT = false; + CPU_INT(2, 4); + } + + schedulepath3msk = 0; +} +static void Vif1CMDMskPath3() // MSKPATH3 +{ + if (vif1ch->chcr.STR) + { + schedulepath3msk = 0x10 | ((vif1Regs->code >> 15) & 0x1); + vif1.vifstalled = true; + } + else + { + schedulepath3msk = (vif1Regs->code >> 15) & 0x1; + Vif1MskPath3(); + } + vif1.cmd &= ~0x7f; +} + + +static void Vif1CMDMark() // MARK +{ + vif1Regs->mark = (u16)vif1Regs->code; + vif1Regs->stat.MRK = true; + vif1.cmd &= ~0x7f; +} + +static void Vif1CMDFlush() // FLUSH/E/A +{ + vif1FLUSH(); + + if ((vif1.cmd & 0x7f) == 0x13) + { + // Gif is already transferring so wait for it. + if (((Path3progress != STOPPED_MODE) || !vif1Regs->mskpath3) && gif->chcr.STR) + { + vif1Regs->stat.VGW = true; + CPU_INT(2, 4); + } + } + + vif1.cmd &= ~0x7f; +} + +static void Vif1CMDMSCALF() //MSCAL/F +{ + vif1FLUSH(); + vuExecMicro<1>((u16)(vif1Regs->code) << 3); + vif1.cmd &= ~0x7f; +} + +static void Vif1CMDMSCNT() // MSCNT +{ + vuExecMicro<1>(-1); + vif1.cmd &= ~0x7f; +} + +static void Vif1CMDSTMask() // STMASK +{ + vif1.tag.size = 1; +} + +static void Vif1CMDSTRowCol() // STROW / STCOL +{ + vif1.tag.addr = 0; + vif1.tag.size = 4; +} + +static void Vif1CMDMPGTransfer() // MPG +{ + int vifNum = (u8)(vif1Regs->code >> 16); + if(!vifNum) vifNum = 256; + + vif1.tag.addr = (u16)((vif1Regs->code) << 3) & 0x3fff; + vif1.tag.size = vifNum * 2; +} + +static void Vif1CMDDirectHL() // DIRECT/HL +{ + int vifImm = (u16)vif1Regs->code; + if(!vifImm) vif1.tag.size = 65536 << 2; + else vif1.tag.size = vifImm << 2; +} + +static void Vif1CMDNull() // invalid opcode +{ + // if ME1, then force the vif to interrupt + + if (!(vif1Regs->err.ME1)) //Ignore vifcode and tag mismatch error + { + Console.WriteLn("UNKNOWN VifCmd: %x\n", vif1.cmd); + vif1Regs->stat.ER1 = true; + vif1.irq++; + } + vif1.cmd = 0; +} + +//------------------------------------------------------------------ +// Vif1 Data Transfer / Vif1 CMD Tables +//------------------------------------------------------------------ + +int (__fastcall *Vif1TransTLB[128])(u32 *data) = +{ + Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x7*/ + Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0xF*/ + Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x17*/ + Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x1F*/ + Vif1TransSTMask , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x27*/ + Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x2F*/ + Vif1TransSTRow , Vif1TransSTCol , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x37*/ + Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x3F*/ + Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x47*/ + Vif1TransNull , Vif1TransNull , Vif1TransMPG , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x4F*/ + Vif1TransDirectHL, Vif1TransDirectHL, Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x57*/ + Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x5F*/ + Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransNull , /*0x67*/ + Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , /*0x6F*/ + Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransNull , /*0x77*/ + Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransNull , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack /*0x7F*/ +}; + +void (*Vif1CMDTLB[82])() = +{ + Vif1CMDNop , Vif1CMDSTCycl , Vif1CMDOffset , Vif1CMDBase , Vif1CMDITop , Vif1CMDSTMod , Vif1CMDMskPath3, Vif1CMDMark , /*0x7*/ + Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0xF*/ + Vif1CMDFlush , Vif1CMDFlush , Vif1CMDNull , Vif1CMDFlush, Vif1CMDMSCALF, Vif1CMDMSCALF, Vif1CMDNull , Vif1CMDMSCNT, /*0x17*/ + Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x1F*/ + Vif1CMDSTMask , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x27*/ + Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x2F*/ + Vif1CMDSTRowCol, Vif1CMDSTRowCol, Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x37*/ + Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x3F*/ + Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x47*/ + Vif1CMDNull , Vif1CMDNull , Vif1CMDMPGTransfer, Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x4F*/ + Vif1CMDDirectHL, Vif1CMDDirectHL +}; diff --git a/pcsx2/Vif1Dma.cpp b/pcsx2/Vif1_Dma.cpp similarity index 56% rename from pcsx2/Vif1Dma.cpp rename to pcsx2/Vif1_Dma.cpp index bca9ebd154..2b41921431 100644 --- a/pcsx2/Vif1Dma.cpp +++ b/pcsx2/Vif1_Dma.cpp @@ -1,1140 +1,684 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2009 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - - -#include "PrecompiledHeader.h" -#include "Common.h" -#include "VifDma.h" -#include "GS.h" -#include "Gif.h" -#include "VUmicro.h" -#include "newVif.h" - -extern void (*Vif1CMDTLB[82])(); -extern int (__fastcall *Vif1TransTLB[128])(u32 *data); - -Path3Modes Path3progress = STOPPED_MODE; -vifStruct vif1; - -static __aligned16 u32 splittransfer[4]; -static u32 splitptr = 0; - -__forceinline void vif1FLUSH() -{ - int _cycles = VU1.cycle; - - // fixme: Same as above, is this a "stalling" offense? I think the cycles should - // be added to cpuRegs.cycle instead of g_vifCycles, but not sure (air) - - if (VU0.VI[REG_VPU_STAT].UL & 0x100) - { - do - { - CpuVU1->ExecuteBlock(); - } - while (VU0.VI[REG_VPU_STAT].UL & 0x100); - - g_vifCycles += (VU1.cycle - _cycles) * BIAS; - } -} - - -void vif1Init() -{ - initNewVif(1); -} - -static __forceinline void vif1UNPACK(u32 *data) -{ - int vifNum; - - if ((vif1Regs->cycle.wl == 0) && (vif1Regs->cycle.wl < vif1Regs->cycle.cl)) - { - Console.WriteLn("Vif1 CL %d, WL %d", vif1Regs->cycle.cl, vif1Regs->cycle.wl); - vif1.cmd &= ~0x7f; - return; - } - - //vif1FLUSH(); - - vif1.usn = (vif1Regs->code >> 14) & 0x1; - vifNum = (vif1Regs->code >> 16) & 0xff; - - if (vifNum == 0) vifNum = 256; - vif1Regs->num = vifNum; - - if (vif1Regs->cycle.wl <= vif1Regs->cycle.cl) - { - vif1.tag.size = ((vifNum * VIFfuncTable[ vif1.cmd & 0xf ].gsize) + 3) >> 2; - } - else - { - int n = vif1Regs->cycle.cl * (vifNum / vif1Regs->cycle.wl) + - _limit(vifNum % vif1Regs->cycle.wl, vif1Regs->cycle.cl); - - vif1.tag.size = ((n * VIFfuncTable[ vif1.cmd & 0xf ].gsize) + 3) >> 2; - } - - if ((vif1Regs->code >> 15) & 0x1) - vif1.tag.addr = (vif1Regs->code + vif1Regs->tops) & 0x3ff; - else - vif1.tag.addr = vif1Regs->code & 0x3ff; - - vif1Regs->offset = 0; - vif1.cl = 0; - vif1.tag.addr <<= 4; - vif1.tag.cmd = vif1.cmd; - -} - -static __forceinline void vif1mpgTransfer(u32 addr, u32 *data, int size) -{ - /* Console.WriteLn("vif1mpgTransfer addr=%x; size=%x", addr, size); - { - FILE *f = fopen("vu1.raw", "wb"); - fwrite(data, 1, size*4, f); - fclose(f); - }*/ - pxAssume(VU1.Micro > 0); - if (memcmp(VU1.Micro + addr, data, size << 2)) - { - CpuVU1->Clear(addr, size << 2); // Clear before writing! :/ - memcpy_fast(VU1.Micro + addr, data, size << 2); - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Vif1 Data Transfer Commands -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -static int __fastcall Vif1TransNull(u32 *data) // Shouldnt go here -{ - Console.WriteLn("VIF1 Shouldn't go here CMD = %x", vif1Regs->code); - vif1.cmd = 0; - return 0; -} - -static int __fastcall Vif1TransSTMask(u32 *data) // STMASK -{ - vif1Regs->mask = data[0]; - VIF_LOG("STMASK == %x", vif1Regs->mask); - - vif1.tag.size = 0; - vif1.cmd = 0; - return 1; -} - -static int __fastcall Vif1TransSTRow(u32 *data) // STROW -{ - int ret; - - u32* pmem = &vif1Regs->r0 + (vif1.tag.addr << 2); - u32* pmem2 = g_vifmask.Row1 + vif1.tag.addr; - pxAssume(vif1.tag.addr < 4); - ret = min(4 - vif1.tag.addr, vif1.vifpacketsize); - pxAssume(ret > 0); - - switch (ret) - { - case 4: - pmem[12] = data[3]; - pmem2[3] = data[3]; - case 3: - pmem[8] = data[2]; - pmem2[2] = data[2]; - case 2: - pmem[4] = data[1]; - pmem2[1] = data[1]; - case 1: - pmem[0] = data[0]; - pmem2[0] = data[0]; - break; - jNO_DEFAULT; - } - - vif1.tag.addr += ret; - vif1.tag.size -= ret; - if (vif1.tag.size == 0) vif1.cmd = 0; - - return ret; -} - -static int __fastcall Vif1TransSTCol(u32 *data) -{ - int ret; - - u32* pmem = &vif1Regs->c0 + (vif1.tag.addr << 2); - u32* pmem2 = g_vifmask.Col1 + vif1.tag.addr; - ret = min(4 - vif1.tag.addr, vif1.vifpacketsize); - switch (ret) - { - case 4: - pmem[12] = data[3]; - pmem2[3] = data[3]; - case 3: - pmem[8] = data[2]; - pmem2[2] = data[2]; - case 2: - pmem[4] = data[1]; - pmem2[1] = data[1]; - case 1: - pmem[0] = data[0]; - pmem2[0] = data[0]; - break; - jNO_DEFAULT; - } - vif1.tag.addr += ret; - vif1.tag.size -= ret; - if (vif1.tag.size == 0) vif1.cmd = 0; - return ret; -} - -static int __fastcall Vif1TransMPG(u32 *data) -{ - if (vif1.vifpacketsize < vif1.tag.size) - { - if((vif1.tag.addr + vif1.vifpacketsize) > 0x4000) DevCon.Warning("Vif1 MPG Split Overflow"); - vif1mpgTransfer(vif1.tag.addr, data, vif1.vifpacketsize); - vif1.tag.addr += vif1.vifpacketsize << 2; - vif1.tag.size -= vif1.vifpacketsize; - return vif1.vifpacketsize; - } - else - { - int ret; - if((vif1.tag.addr + vif1.tag.size) > 0x4000) DevCon.Warning("Vif1 MPG Overflow"); - vif1mpgTransfer(vif1.tag.addr, data, vif1.tag.size); - ret = vif1.tag.size; - vif1.tag.size = 0; - vif1.cmd = 0; - return ret; - } -} - -// Dummy GIF-TAG Packet to Guarantee Count = 1 -extern __aligned16 u32 nloop0_packet[4]; - -static int __fastcall Vif1TransDirectHL(u32 *data) -{ - int ret = 0; - - if ((vif1.cmd & 0x7f) == 0x51) - { - if (gif->chcr.STR && (!vif1Regs->mskpath3 && (Path3progress == IMAGE_MODE))) //PATH3 is in image mode, so wait for end of transfer - { - vif1Regs->stat.VGW = true; - return 0; - } - } - - gifRegs->stat.APATH |= GIF_APATH2; - gifRegs->stat.OPH = true; - - if (splitptr > 0) //Leftover data from the last packet, filling the rest and sending to the GS - { - if ((splitptr < 4) && (vif1.vifpacketsize >= (4 - splitptr))) - { - while (splitptr < 4) - { - splittransfer[splitptr++] = (u32)data++; - ret++; - vif1.tag.size--; - } - } - - Registers::Freeze(); - // copy 16 bytes the fast way: - const u64* src = (u64*)splittransfer[0]; - GetMTGS().PrepDataPacket(GIF_PATH_2, nloop0_packet, 1); - u64* dst = (u64*)GetMTGS().GetDataPacketPtr(); - dst[0] = src[0]; - dst[1] = src[1]; - - GetMTGS().SendDataPacket(); - Registers::Thaw(); - - if (vif1.tag.size == 0) vif1.cmd = 0; - splitptr = 0; - return ret; - } - - if (vif1.vifpacketsize < vif1.tag.size) - { - if (vif1.vifpacketsize < 4 && splitptr != 4) //Not a full QW left in the buffer, saving left over data - { - ret = vif1.vifpacketsize; - while (ret > 0) - { - splittransfer[splitptr++] = (u32)data++; - vif1.tag.size--; - ret--; - } - return vif1.vifpacketsize; - } - vif1.tag.size -= vif1.vifpacketsize; - ret = vif1.vifpacketsize; - } - else - { - gifRegs->stat.clear_flags(GIF_STAT_APATH2 | GIF_STAT_OPH); - ret = vif1.tag.size; - vif1.tag.size = 0; - vif1.cmd = 0; - } - - //TODO: ret is guaranteed to be qword aligned ? - - Registers::Freeze(); - - // Round ret up, just in case it's not 128bit aligned. - const uint count = GetMTGS().PrepDataPacket(GIF_PATH_2, data, (ret + 3) >> 2); - memcpy_fast(GetMTGS().GetDataPacketPtr(), data, count << 4); - GetMTGS().SendDataPacket(); - - Registers::Thaw(); - - return ret; -} -static int __fastcall Vif1TransUnpack(u32 *data) -{ - return nVifUnpack(1, (u8*)data); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Vif1 CMD Base Commands -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -static void Vif1CMDNop() // NOP -{ - vif1.cmd &= ~0x7f; -} - -static void Vif1CMDSTCycl() // STCYCL -{ - vif1Regs->cycle.cl = (u8)vif1Regs->code; - vif1Regs->cycle.wl = (u8)(vif1Regs->code >> 8); - vif1.cmd &= ~0x7f; -} - -static void Vif1CMDOffset() // OFFSET -{ - vif1Regs->ofst = vif1Regs->code & 0x3ff; - vif1Regs->stat.DBF = false; - vif1Regs->tops = vif1Regs->base; - vif1.cmd &= ~0x7f; -} - -static void Vif1CMDBase() // BASE -{ - vif1Regs->base = vif1Regs->code & 0x3ff; - vif1.cmd &= ~0x7f; -} - -static void Vif1CMDITop() // ITOP -{ - vif1Regs->itops = vif1Regs->code & 0x3ff; - vif1.cmd &= ~0x7f; -} - -static void Vif1CMDSTMod() // STMOD -{ - vif1Regs->mode = vif1Regs->code & 0x3; - vif1.cmd &= ~0x7f; -} - -u8 schedulepath3msk = 0; - -void Vif1MskPath3() // MSKPATH3 -{ - vif1Regs->mskpath3 = schedulepath3msk & 0x1; - //Console.WriteLn("VIF MSKPATH3 %x", vif1Regs->mskpath3); - - if (vif1Regs->mskpath3) - { - gifRegs->stat.M3P = true; - } - else - { - //Let the Gif know it can transfer again (making sure any vif stall isnt unset prematurely) - Path3progress = TRANSFER_MODE; - gifRegs->stat.IMT = false; - CPU_INT(2, 4); - } - - schedulepath3msk = 0; -} -static void Vif1CMDMskPath3() // MSKPATH3 -{ - if (vif1ch->chcr.STR) - { - schedulepath3msk = 0x10 | ((vif1Regs->code >> 15) & 0x1); - vif1.vifstalled = true; - } - else - { - schedulepath3msk = (vif1Regs->code >> 15) & 0x1; - Vif1MskPath3(); - } - vif1.cmd &= ~0x7f; -} - - -static void Vif1CMDMark() // MARK -{ - vif1Regs->mark = (u16)vif1Regs->code; - vif1Regs->stat.MRK = true; - vif1.cmd &= ~0x7f; -} - -static void Vif1CMDFlush() // FLUSH/E/A -{ - vif1FLUSH(); - - if ((vif1.cmd & 0x7f) == 0x13) - { - // Gif is already transferring so wait for it. - if (((Path3progress != STOPPED_MODE) || !vif1Regs->mskpath3) && gif->chcr.STR) - { - vif1Regs->stat.VGW = true; - CPU_INT(2, 4); - } - } - - vif1.cmd &= ~0x7f; -} - -static void Vif1CMDMSCALF() //MSCAL/F -{ - vif1FLUSH(); - vuExecMicro<1>((u16)(vif1Regs->code) << 3); - vif1.cmd &= ~0x7f; -} - -static void Vif1CMDMSCNT() // MSCNT -{ - vuExecMicro<1>(-1); - vif1.cmd &= ~0x7f; -} - -static void Vif1CMDSTMask() // STMASK -{ - vif1.tag.size = 1; -} - -static void Vif1CMDSTRowCol() // STROW / STCOL -{ - vif1.tag.addr = 0; - vif1.tag.size = 4; -} - -static void Vif1CMDMPGTransfer() // MPG -{ - int vifNum; - //vif1FLUSH(); - vifNum = (u8)(vif1Regs->code >> 16); - - if (vifNum == 0) vifNum = 256; - - vif1.tag.addr = (u16)((vif1Regs->code) << 3) & 0x3fff; - vif1.tag.size = vifNum * 2; -} - -static void Vif1CMDDirectHL() // DIRECT/HL -{ - int vifImm; - vifImm = (u16)vif1Regs->code; - - if (vifImm == 0) - vif1.tag.size = 65536 << 2; - else - vif1.tag.size = vifImm << 2; -} - -static void Vif1CMDNull() // invalid opcode -{ - // if ME1, then force the vif to interrupt - - if (!(vif1Regs->err.ME1)) //Ignore vifcode and tag mismatch error - { - Console.WriteLn("UNKNOWN VifCmd: %x\n", vif1.cmd); - vif1Regs->stat.ER1 = true; - vif1.irq++; - } - vif1.cmd = 0; -} - -// Vif1 Data Transfer Table - -int (__fastcall *Vif1TransTLB[128])(u32 *data) = -{ - Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x7*/ - Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0xF*/ - Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x17*/ - Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x1F*/ - Vif1TransSTMask , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x27*/ - Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x2F*/ - Vif1TransSTRow , Vif1TransSTCol , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x37*/ - Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x3F*/ - Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x47*/ - Vif1TransNull , Vif1TransNull , Vif1TransMPG , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x4F*/ - Vif1TransDirectHL, Vif1TransDirectHL, Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x57*/ - Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x5F*/ - Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransNull , /*0x67*/ - Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , /*0x6F*/ - Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransNull , /*0x77*/ - Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransNull , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack /*0x7F*/ -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Vif1 CMD Table -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void (*Vif1CMDTLB[82])() = -{ - Vif1CMDNop , Vif1CMDSTCycl , Vif1CMDOffset , Vif1CMDBase , Vif1CMDITop , Vif1CMDSTMod , Vif1CMDMskPath3, Vif1CMDMark , /*0x7*/ - Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0xF*/ - Vif1CMDFlush , Vif1CMDFlush , Vif1CMDNull , Vif1CMDFlush, Vif1CMDMSCALF, Vif1CMDMSCALF, Vif1CMDNull , Vif1CMDMSCNT, /*0x17*/ - Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x1F*/ - Vif1CMDSTMask , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x27*/ - Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x2F*/ - Vif1CMDSTRowCol, Vif1CMDSTRowCol, Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x37*/ - Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x3F*/ - Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x47*/ - Vif1CMDNull , Vif1CMDNull , Vif1CMDMPGTransfer, Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x4F*/ - Vif1CMDDirectHL, Vif1CMDDirectHL -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool VIF1transfer(u32 *data, int size, bool istag) -{ - int ret; - int transferred = vif1.vifstalled ? vif1.irqoffset : 0; // irqoffset necessary to add up the right qws, or else will spin (spiderman) - - VIF_LOG("VIF1transfer: size %x (vif1.cmd %x)", size, vif1.cmd); - - vif1.irqoffset = 0; - vif1.vifstalled = false; - vif1.stallontag = false; - vif1.vifpacketsize = size; - - while (vif1.vifpacketsize > 0) - { - if(vif1Regs->stat.VGW) break; - - if (vif1.cmd) - { - vif1Regs->stat.VPS = VPS_TRANSFERRING; //Decompression has started - - ret = Vif1TransTLB[vif1.cmd](data); - data += ret; - vif1.vifpacketsize -= ret; - - //We are once again waiting for a new vifcode as the command has cleared - if (vif1.cmd == 0) vif1Regs->stat.VPS = VPS_IDLE; - continue; - } - - if (vif1.tag.size != 0) DevCon.Error("no vif1 cmd but tag size is left last cmd read %x", vif1Regs->code); - - if (vif1.irq) break; - - vif1.cmd = (data[0] >> 24); - vif1Regs->code = data[0]; - vif1Regs->stat.VPS |= VPS_DECODING; - - if ((vif1.cmd & 0x60) == 0x60) - { - vif1UNPACK(data); - } - else - { - VIF_LOG("VIFtransfer: cmd %x, num %x, imm %x, size %x", vif1.cmd, (data[0] >> 16) & 0xff, data[0] & 0xffff, vif1.vifpacketsize); - - if ((vif1.cmd & 0x7f) > 0x51) - { - if (!(vif0Regs->err.ME1)) //Ignore vifcode and tag mismatch error - { - Console.WriteLn("UNKNOWN VifCmd: %x", vif1.cmd); - vif1Regs->stat.ER1 = true; - vif1.irq++; - } - vif1.cmd = 0; - } - else Vif1CMDTLB[(vif1.cmd & 0x7f)](); - } - - ++data; - --vif1.vifpacketsize; - - if ((vif1.cmd & 0x80)) - { - vif1.cmd &= 0x7f; - - if (!(vif1Regs->err.MII)) //i bit on vifcode and not masked by VIF1_ERR - { - VIF_LOG("Interrupt on VIFcmd: %x (INTC_MASK = %x)", vif1.cmd, psHu32(INTC_MASK)); - - ++vif1.irq; - - if (istag && vif1.tag.size <= vif1.vifpacketsize) vif1.stallontag = true; - - if (vif1.tag.size == 0) break; - } - } - - if(!vif1.cmd) vif1Regs->stat.VPS = VPS_IDLE; - - if((vif1Regs->stat.VGW) || vif1.vifstalled == true) break; - } // End of Transfer loop - - transferred += size - vif1.vifpacketsize; - g_vifCycles += (transferred >> 2) * BIAS; /* guessing */ - vif1.irqoffset = transferred % 4; // cannot lose the offset - - if (vif1.irq && vif1.cmd == 0) - { - vif1.vifstalled = true; - - if (((vif1Regs->code >> 24) & 0x7f) != 0x7) vif1Regs->stat.VIS = true; // Note: commenting this out fixes WALL-E - - if (vif1ch->qwc == 0 && (vif1.irqoffset == 0 || istag == 1)) vif1.inprogress &= ~0x1; - - // spiderman doesn't break on qw boundaries - if (istag) return false; - - transferred = transferred >> 2; - vif1ch->madr += (transferred << 4); - vif1ch->qwc -= transferred; - - if ((vif1ch->qwc == 0) && (vif1.irqoffset == 0)) vif1.inprogress = 0; - //Console.WriteLn("Stall on vif1, FromSPR = %x, Vif1MADR = %x Sif0MADR = %x STADR = %x", psHu32(0x1000d010), vif1ch->madr, psHu32(0x1000c010), psHu32(DMAC_STADR)); - return false; - } - - vif1Regs->stat.VPS = VPS_IDLE; //Vif goes idle as the stall happened between commands; - if (vif1.cmd) vif1Regs->stat.VPS = VPS_WAITING; //Otherwise we wait for the data - - if (!istag) - { - transferred = transferred >> 2; - vif1ch->madr += (transferred << 4); - vif1ch->qwc -= transferred; - } - - if (vif1Regs->stat.VGW) vif1.vifstalled = true; - - if (vif1ch->qwc == 0 && (vif1.irqoffset == 0 || istag == 1)) vif1.inprogress &= ~0x1; - - return (!(vif1.vifstalled)); -} - -void vif1TransferFromMemory() -{ - int size; - u64* pMem = (u64*)dmaGetAddr(vif1ch->madr); - - // VIF from gsMemory - if (pMem == NULL) //Is vif0ptag empty? - { - Console.WriteLn("Vif1 Tag BUSERR"); - dmacRegs->stat.BEIS = true; //Bus Error - vif1Regs->stat.FQC = 0; - - vif1ch->qwc = 0; - vif1.done = true; - CPU_INT(1, 0); - return; //An error has occurred. - } - - // MTGS concerns: The MTGS is inherently disagreeable with the idea of downloading - // stuff from the GS. The *only* way to handle this case safely is to flush the GS - // completely and execute the transfer there-after. - - XMMRegisters::Freeze(); - - if (GSreadFIFO2 == NULL) - { - for (size = vif1ch->qwc; size > 0; --size) - { - if (size > 1) - { - GetMTGS().WaitGS(); - GSreadFIFO(&psHu64(VIF1_FIFO)); - } - pMem[0] = psHu64(VIF1_FIFO); - pMem[1] = psHu64(VIF1_FIFO + 8); - pMem += 2; - } - } - else - { - GetMTGS().WaitGS(); - GSreadFIFO2(pMem, vif1ch->qwc); - - // set incase read - psHu64(VIF1_FIFO) = pMem[2*vif1ch->qwc-2]; - psHu64(VIF1_FIFO + 8) = pMem[2*vif1ch->qwc-1]; - } - - XMMRegisters::Thaw(); - - g_vifCycles += vif1ch->qwc * 2; - vif1ch->madr += vif1ch->qwc * 16; // mgs3 scene changes - vif1ch->qwc = 0; -} - -bool _VIF1chain() -{ - u32 *pMem; - - if (vif1ch->qwc == 0) - { - vif1.inprogress = 0; - return true; - } - - if (vif1.dmamode == VIF_NORMAL_FROM_MEM_MODE) - { - vif1TransferFromMemory(); - vif1.inprogress = 0; - return true; - } - - pMem = (u32*)dmaGetAddr(vif1ch->madr); - if (pMem == NULL) - { - vif1.cmd = 0; - vif1.tag.size = 0; - vif1ch->qwc = 0; - return true; - } - - VIF_LOG("VIF1chain size=%d, madr=%lx, tadr=%lx", - vif1ch->qwc, vif1ch->madr, vif1ch->tadr); - - if (vif1.vifstalled) - return VIF1transfer(pMem + vif1.irqoffset, vif1ch->qwc * 4 - vif1.irqoffset, false); - else - return VIF1transfer(pMem, vif1ch->qwc * 4, false); -} - -bool _chainVIF1() -{ - return vif1.done; // Return Done -} - -__forceinline void vif1SetupTransfer() -{ - tDMA_TAG *ptag; - - switch (vif1.dmamode) - { - case VIF_NORMAL_TO_MEM_MODE: - case VIF_NORMAL_FROM_MEM_MODE: - vif1.inprogress = 1; - vif1.done = true; - g_vifCycles = 2; - break; - - case VIF_CHAIN_MODE: - ptag = dmaGetAddr(vif1ch->tadr); //Set memory pointer to TADR - - if (!(vif1ch->transfer("Vif1 Tag", ptag))) return; - - vif1ch->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("VIF1 Tag %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx\n", - ptag[1]._u32, ptag[0]._u32, vif1ch->qwc, ptag->ID, vif1ch->madr, vif1ch->tadr); - - if (!vif1.done && ((dmacRegs->ctrl.STD == STD_VIF1) && (ptag->ID == TAG_REFS))) // STD == VIF1 - { - // there are still bugs, need to also check if gif->madr +16*qwc >= stadr, if not, stall - if ((vif1ch->madr + vif1ch->qwc * 16) >= dmacRegs->stadr.ADDR) - { - // stalled - hwDmacIrq(DMAC_STALL_SIS); - return; - } - } - - vif1.inprogress = 1; - - if (vif1ch->chcr.TTE) - { - bool ret; - - if (vif1.vifstalled) - ret = VIF1transfer((u32*)ptag + (2 + vif1.irqoffset), 2 - vif1.irqoffset, true); //Transfer Tag on stall - else - ret = VIF1transfer((u32*)ptag + 2, 2, true); //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 - } - } - - vif1.irqoffset = 0; - vif1.done |= hwDmacSrcChainWithStack(vif1ch, ptag->ID); - - //Check TIE bit of CHCR and IRQ bit of tag - if (vif1ch->chcr.TIE && ptag->IRQ) - { - VIF_LOG("dmaIrq Set"); - - //End Transfer - vif1.done = true; - return; - } - break; - } -} - -__forceinline void vif1Interrupt() -{ - VIF_LOG("vif1Interrupt: %8.8x", cpuRegs.cycle); - - g_vifCycles = 0; - - if (schedulepath3msk) Vif1MskPath3(); - - if ((vif1Regs->stat.VGW)) - { - if (gif->chcr.STR) - { - CPU_INT(1, gif->qwc * BIAS); - return; - } - else - { - vif1Regs->stat.VGW = false; - } - } - - if (!(vif1ch->chcr.STR)) Console.WriteLn("Vif1 running when CHCR == %x", vif1ch->chcr._u32); - - if (vif1.irq && vif1.tag.size == 0) - { - vif1Regs->stat.INT = true; - hwIntcIrq(VIF1intc); - --vif1.irq; - if (vif1Regs->stat.test(VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS)) - { - 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(13, vif1ch->qwc * BIAS); - } - } - - if (vif1.inprogress & 0x1) - { - _VIF1chain(); - CPU_INT(1, /*g_vifCycles*/ VifCycleVoodoo); - return; - } - - if (!vif1.done) - { - - if (!(dmacRegs->ctrl.DMAE)) - { - Console.WriteLn("vif1 dma masked"); - return; - } - - if ((vif1.inprogress & 0x1) == 0) vif1SetupTransfer(); - - CPU_INT(1, /*g_vifCycles*/ VifCycleVoodoo); - return; - } - - if (vif1.vifstalled && vif1.irq) - { - CPU_INT(1, 0); - return; //Dont want to end if vif is stalled. - } -#ifdef PCSX2_DEVBUILD - if (vif1ch->qwc > 0) Console.WriteLn("VIF1 Ending with %x QWC left"); - 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; - vif1ch->chcr.STR = false; - g_vifCycles = 0; - hwDmacIrq(DMAC_VIF1); - - //Im not totally sure why Path3 Masking makes it want to see stuff in the fifo - //Games effected by setting, Fatal Frame, KH2, Shox, Crash N Burn, GT3/4 possibly - //Im guessing due to the full gs fifo before the reverse? (Refraction) - //Note also this is only the condition for reverse fifo mode, normal direction clears it as normal - if (!vif1Regs->mskpath3 || vif1ch->chcr.DIR) vif1Regs->stat.FQC = 0; -} - -void dmaVIF1() -{ - VIF_LOG("dmaVIF1 chcr = %lx, madr = %lx, qwc = %lx\n" - " tadr = %lx, asr0 = %lx, asr1 = %lx", - vif1ch->chcr._u32, vif1ch->madr, vif1ch->qwc, - vif1ch->tadr, vif1ch->asr0, vif1ch->asr1); - - g_vifCycles = 0; - vif1.inprogress = 0; - - if (dmacRegs->ctrl.MFD == MFD_VIF1) // VIF MFIFO - { - //Console.WriteLn("VIFMFIFO\n"); - // Test changed because the Final Fantasy 12 opening somehow has the tag in *Undefined* mode, which is not in the documentation that I saw. - if (vif1ch->chcr.MOD == NORMAL_MODE) Console.WriteLn("MFIFO mode is normal (which isn't normal here)! %x", vif1ch->chcr._u32); - vifMFIFOInterrupt(); - return; - } - -#ifdef PCSX2_DEVBUILD - if (dmacRegs->ctrl.STD == STD_VIF1) - { - //DevCon.WriteLn("VIF Stall Control Source = %x, Drain = %x", (psHu32(0xe000) >> 4) & 0x3, (psHu32(0xe000) >> 6) & 0x3); - } -#endif - - if ((vif1ch->chcr.MOD == NORMAL_MODE) || vif1ch->qwc > 0) // Normal Mode - { - - if (dmacRegs->ctrl.STD == STD_VIF1) - Console.WriteLn("DMA Stall Control on VIF1 normal"); - - if (vif1ch->chcr.DIR) // to Memory - vif1.dmamode = VIF_NORMAL_TO_MEM_MODE; - else - vif1.dmamode = VIF_NORMAL_FROM_MEM_MODE; - } - else - { - vif1.dmamode = VIF_CHAIN_MODE; - } - - if (vif1.dmamode != VIF_NORMAL_FROM_MEM_MODE) - vif1Regs->stat.FQC = 0x10; - else - vif1Regs->stat.FQC = min((u16)0x10, vif1ch->qwc); - - // Chain Mode - vif1.done = false; - vif1Interrupt(); -} - -void vif1Write32(u32 mem, u32 value) -{ - switch (mem) - { - case VIF1_MARK: - VIF_LOG("VIF1_MARK write32 0x%8.8x", value); - - /* Clear mark flag in VIF1_STAT and set mark with 'value' */ - vif1Regs->stat.MRK = false; - vif1Regs->mark = value; - break; - - case VIF1_FBRST: // FBRST - VIF_LOG("VIF1_FBRST write32 0x%8.8x", value); - - if (FBRST(value).RST) // Reset Vif. - { - memzero(vif1); - cpuRegs.interrupt &= ~((1 << 1) | (1 << 10)); //Stop all vif1 DMA's - vif1ch->qwc = 0; //? - psHu64(VIF1_FIFO) = 0; - psHu64(VIF1_FIFO + 8) = 0; - vif1.done = true; - - if(vif1Regs->mskpath3) - { - vif1Regs->mskpath3 = 0; - gifRegs->stat.IMT = false; - if (gif->chcr.STR) CPU_INT(2, 4); - } - - vif1Regs->err.reset(); - vif1.inprogress = 0; - 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); - } - - if (FBRST(value).FBK) // Forcebreak Vif. - { - /* I guess we should stop the VIF dma here, but not 100% sure (linuz) */ - vif1Regs->stat.VFS = true; - vif1Regs->stat.VPS = VPS_IDLE; - cpuRegs.interrupt &= ~((1 << 1) | (1 << 10)); //Stop all vif1 DMA's - vif1.vifstalled = true; - Console.WriteLn("vif1 force break"); - } - - if (FBRST(value).STP) // Stop Vif. - { - // Not completely sure about this, can't remember what game used this, but 'draining' the VIF helped it, instead of - // just stoppin the VIF (linuz). - vif1Regs->stat.VSS = true; - vif1Regs->stat.VPS = VPS_IDLE; - cpuRegs.interrupt &= ~((1 << 1) | (1 << 10)); //Stop all vif1 DMA's - vif1.vifstalled = true; - } - - if (FBRST(value).STC) // Cancel Vif Stall. - { - bool cancel = false; - - /* Cancel stall, first check if there is a stall to cancel, and then clear VIF1_STAT VSS|VFS|VIS|INT|ER0|ER1 bits */ - if (vif1Regs->stat.test(VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS)) - { - cancel = true; - } - - vif1Regs->stat.clear_flags(VIF1_STAT_VSS | VIF1_STAT_VFS | VIF1_STAT_VIS | - VIF1_STAT_INT | VIF1_STAT_ER0 | VIF1_STAT_ER1); - - if (cancel) - { - if (vif1.vifstalled) - { - g_vifCycles = 0; - // loop necessary for spiderman - switch(dmacRegs->ctrl.MFD) - { - case MFD_VIF1: - //Console.WriteLn("MFIFO Stall"); - CPU_INT(10, vif1ch->qwc * BIAS); - break; - - case NO_MFD: - case MFD_RESERVED: - case MFD_GIF: // Wonder if this should be with VIF? - // Gets the timing right - Flatout - CPU_INT(1, vif1ch->qwc * BIAS); - break; - } - - vif1ch->chcr.STR = true; - } - } - } - break; - - case VIF1_ERR: // ERR - VIF_LOG("VIF1_ERR write32 0x%8.8x", value); - - /* Set VIF1_ERR with 'value' */ - vif1Regs->err.write(value); - break; - - case VIF1_STAT: // STAT - VIF_LOG("VIF1_STAT write32 0x%8.8x", value); - -#ifdef PCSX2_DEVBUILD - /* Only FDR bit is writable, so mask the rest */ - if ((vif1Regs->stat.FDR) ^ ((tVIF_STAT&)value).FDR) - { - // different so can't be stalled - if (vif1Regs->stat.test(VIF1_STAT_INT | VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS)) - { - DevCon.WriteLn("changing dir when vif1 fifo stalled"); - } - } -#endif - - vif1Regs->stat.FDR = VIF_STAT(value).FDR; - - if (vif1Regs->stat.FDR) // Vif transferring to memory. - { - // Hack but it checks this is true before transfer? (fatal frame) - vif1Regs->stat.FQC = 0x1; - } - else // Memory transferring to Vif. - { - vif1ch->qwc = 0; - vif1.vifstalled = false; - vif1.done = true; - vif1Regs->stat.FQC = 0; - } - break; - - case VIF1_MODE: - vif1Regs->mode = value; - break; - - case VIF1_R0: - case VIF1_R1: - case VIF1_R2: - case VIF1_R3: - pxAssume((mem&0xf) == 0); - g_vifmask.Row1[(mem>>4) & 3] = value; - break; - - case VIF1_C0: - case VIF1_C1: - case VIF1_C2: - case VIF1_C3: - pxAssume((mem&0xf) == 0); - g_vifmask.Col1[(mem>>4) & 3] = value; - break; - - default: - Console.WriteLn("Unknown Vif1 write to %x", mem); - psHu32(mem) = value; - break; - } - - /* Other registers are read-only so do nothing for them */ -} - -void vif1Reset() -{ - /* Reset the whole VIF, meaning the internal pcsx2 vars, and all the registers */ - memzero(vif1); - memzero(*vif1Regs); - - psHu64(VIF1_FIFO) = 0; - psHu64(VIF1_FIFO + 8) = 0; - - vif1Regs->stat.VPS = VPS_IDLE; - vif1Regs->stat.FQC = 0; // FQC=0 - - vif1.done = true; - cpuRegs.interrupt &= ~((1 << 1) | (1 << 10)); //Stop all vif1 DMA's - - resetNewVif(1); -} - -void SaveStateBase::vif1Freeze() -{ - static u32 g_vif1Masks[64]; // Dummy Var for saved state compatibility - static u32 g_vif1HasMask3[4]; // Dummy Var for saved state compatibility - Freeze(vif1); - - Freeze(g_vif1HasMask3); // Not Used Anymore - Freeze(g_vif1Masks); // Not Used Anymore -} +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2009 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#include "PrecompiledHeader.h" +#include "Common.h" +#include "Vif_Dma.h" +#include "GS.h" +#include "Gif.h" +#include "VUmicro.h" +#include "newVif.h" + +extern void (*Vif1CMDTLB[82])(); +extern int (__fastcall *Vif1TransTLB[128])(u32 *data); + +Path3Modes Path3progress = STOPPED_MODE; +vifStruct vif1; + +__forceinline void vif1FLUSH() +{ + int _cycles = VU1.cycle; + + // fixme: Same as above, is this a "stalling" offense? I think the cycles should + // be added to cpuRegs.cycle instead of g_vifCycles, but not sure (air) + + if (VU0.VI[REG_VPU_STAT].UL & 0x100) + { + do + { + CpuVU1->ExecuteBlock(); + } + while (VU0.VI[REG_VPU_STAT].UL & 0x100); + + g_vifCycles += (VU1.cycle - _cycles) * BIAS; + } +} + +static __forceinline void vif1UNPACK(u32 *data) +{ + int vifNum; + + if ((vif1Regs->cycle.wl == 0) && (vif1Regs->cycle.wl < vif1Regs->cycle.cl)) + { + Console.WriteLn("Vif1 CL %d, WL %d", vif1Regs->cycle.cl, vif1Regs->cycle.wl); + vif1.cmd &= ~0x7f; + return; + } + + //vif1FLUSH(); + + vif1.usn = (vif1Regs->code >> 14) & 0x1; + vifNum = (vif1Regs->code >> 16) & 0xff; + + if (vifNum == 0) vifNum = 256; + vif1Regs->num = vifNum; + + if (vif1Regs->cycle.wl <= vif1Regs->cycle.cl) + { + vif1.tag.size = ((vifNum * VIFfuncTable[ vif1.cmd & 0xf ].gsize) + 3) >> 2; + } + else + { + int n = vif1Regs->cycle.cl * (vifNum / vif1Regs->cycle.wl) + + _limit(vifNum % vif1Regs->cycle.wl, vif1Regs->cycle.cl); + + vif1.tag.size = ((n * VIFfuncTable[ vif1.cmd & 0xf ].gsize) + 3) >> 2; + } + + if ((vif1Regs->code >> 15) & 0x1) + vif1.tag.addr = (vif1Regs->code + vif1Regs->tops) & 0x3ff; + else + vif1.tag.addr = vif1Regs->code & 0x3ff; + + vif1Regs->offset = 0; + vif1.cl = 0; + vif1.tag.addr <<= 4; + vif1.tag.cmd = vif1.cmd; + +} + +bool VIF1transfer(u32 *data, int size, bool istag) +{ + int ret; + int transferred = vif1.vifstalled ? vif1.irqoffset : 0; // irqoffset necessary to add up the right qws, or else will spin (spiderman) + + VIF_LOG("VIF1transfer: size %x (vif1.cmd %x)", size, vif1.cmd); + + vif1.irqoffset = 0; + vif1.vifstalled = false; + vif1.stallontag = false; + vif1.vifpacketsize = size; + + while (vif1.vifpacketsize > 0) + { + if(vif1Regs->stat.VGW) break; + + if (vif1.cmd) + { + vif1Regs->stat.VPS = VPS_TRANSFERRING; //Decompression has started + + ret = Vif1TransTLB[vif1.cmd](data); + data += ret; + vif1.vifpacketsize -= ret; + + //We are once again waiting for a new vifcode as the command has cleared + if (vif1.cmd == 0) vif1Regs->stat.VPS = VPS_IDLE; + continue; + } + + if (vif1.tag.size != 0) DevCon.Error("no vif1 cmd but tag size is left last cmd read %x", vif1Regs->code); + + if (vif1.irq) break; + + vif1.cmd = (data[0] >> 24); + vif1Regs->code = data[0]; + vif1Regs->stat.VPS |= VPS_DECODING; + + if ((vif1.cmd & 0x60) == 0x60) + { + vif1UNPACK(data); + } + else + { + VIF_LOG("VIFtransfer: cmd %x, num %x, imm %x, size %x", vif1.cmd, (data[0] >> 16) & 0xff, data[0] & 0xffff, vif1.vifpacketsize); + + if ((vif1.cmd & 0x7f) > 0x51) + { + if (!(vif0Regs->err.ME1)) //Ignore vifcode and tag mismatch error + { + Console.WriteLn("UNKNOWN VifCmd: %x", vif1.cmd); + vif1Regs->stat.ER1 = true; + vif1.irq++; + } + vif1.cmd = 0; + } + else Vif1CMDTLB[(vif1.cmd & 0x7f)](); + } + + ++data; + --vif1.vifpacketsize; + + if ((vif1.cmd & 0x80)) + { + vif1.cmd &= 0x7f; + + if (!(vif1Regs->err.MII)) //i bit on vifcode and not masked by VIF1_ERR + { + VIF_LOG("Interrupt on VIFcmd: %x (INTC_MASK = %x)", vif1.cmd, psHu32(INTC_MASK)); + + ++vif1.irq; + + if (istag && vif1.tag.size <= vif1.vifpacketsize) vif1.stallontag = true; + + if (vif1.tag.size == 0) break; + } + } + + if(!vif1.cmd) vif1Regs->stat.VPS = VPS_IDLE; + + if((vif1Regs->stat.VGW) || vif1.vifstalled == true) break; + } // End of Transfer loop + + transferred += size - vif1.vifpacketsize; + g_vifCycles += (transferred >> 2) * BIAS; /* guessing */ + vif1.irqoffset = transferred % 4; // cannot lose the offset + + if (vif1.irq && vif1.cmd == 0) + { + vif1.vifstalled = true; + + if (((vif1Regs->code >> 24) & 0x7f) != 0x7) vif1Regs->stat.VIS = true; // Note: commenting this out fixes WALL-E + + if (vif1ch->qwc == 0 && (vif1.irqoffset == 0 || istag == 1)) vif1.inprogress &= ~0x1; + + // spiderman doesn't break on qw boundaries + if (istag) return false; + + transferred = transferred >> 2; + vif1ch->madr += (transferred << 4); + vif1ch->qwc -= transferred; + + if ((vif1ch->qwc == 0) && (vif1.irqoffset == 0)) vif1.inprogress = 0; + //Console.WriteLn("Stall on vif1, FromSPR = %x, Vif1MADR = %x Sif0MADR = %x STADR = %x", psHu32(0x1000d010), vif1ch->madr, psHu32(0x1000c010), psHu32(DMAC_STADR)); + return false; + } + + vif1Regs->stat.VPS = VPS_IDLE; //Vif goes idle as the stall happened between commands; + if (vif1.cmd) vif1Regs->stat.VPS = VPS_WAITING; //Otherwise we wait for the data + + if (!istag) + { + transferred = transferred >> 2; + vif1ch->madr += (transferred << 4); + vif1ch->qwc -= transferred; + } + + if (vif1Regs->stat.VGW) vif1.vifstalled = true; + + if (vif1ch->qwc == 0 && (vif1.irqoffset == 0 || istag == 1)) vif1.inprogress &= ~0x1; + + return (!(vif1.vifstalled)); +} + +void vif1TransferFromMemory() +{ + int size; + u64* pMem = (u64*)dmaGetAddr(vif1ch->madr); + + // VIF from gsMemory + if (pMem == NULL) //Is vif0ptag empty? + { + Console.WriteLn("Vif1 Tag BUSERR"); + dmacRegs->stat.BEIS = true; //Bus Error + vif1Regs->stat.FQC = 0; + + vif1ch->qwc = 0; + vif1.done = true; + CPU_INT(1, 0); + return; //An error has occurred. + } + + // MTGS concerns: The MTGS is inherently disagreeable with the idea of downloading + // stuff from the GS. The *only* way to handle this case safely is to flush the GS + // completely and execute the transfer there-after. + + XMMRegisters::Freeze(); + + if (GSreadFIFO2 == NULL) + { + for (size = vif1ch->qwc; size > 0; --size) + { + if (size > 1) + { + GetMTGS().WaitGS(); + GSreadFIFO(&psHu64(VIF1_FIFO)); + } + pMem[0] = psHu64(VIF1_FIFO); + pMem[1] = psHu64(VIF1_FIFO + 8); + pMem += 2; + } + } + else + { + GetMTGS().WaitGS(); + GSreadFIFO2(pMem, vif1ch->qwc); + + // set incase read + psHu64(VIF1_FIFO) = pMem[2*vif1ch->qwc-2]; + psHu64(VIF1_FIFO + 8) = pMem[2*vif1ch->qwc-1]; + } + + XMMRegisters::Thaw(); + + g_vifCycles += vif1ch->qwc * 2; + vif1ch->madr += vif1ch->qwc * 16; // mgs3 scene changes + vif1ch->qwc = 0; +} + +bool _VIF1chain() +{ + u32 *pMem; + + if (vif1ch->qwc == 0) + { + vif1.inprogress = 0; + return true; + } + + if (vif1.dmamode == VIF_NORMAL_FROM_MEM_MODE) + { + vif1TransferFromMemory(); + vif1.inprogress = 0; + return true; + } + + pMem = (u32*)dmaGetAddr(vif1ch->madr); + if (pMem == NULL) + { + vif1.cmd = 0; + vif1.tag.size = 0; + vif1ch->qwc = 0; + return true; + } + + VIF_LOG("VIF1chain size=%d, madr=%lx, tadr=%lx", + vif1ch->qwc, vif1ch->madr, vif1ch->tadr); + + if (vif1.vifstalled) + return VIF1transfer(pMem + vif1.irqoffset, vif1ch->qwc * 4 - vif1.irqoffset, false); + else + return VIF1transfer(pMem, vif1ch->qwc * 4, false); +} + +bool _chainVIF1() +{ + return vif1.done; // Return Done +} + +__forceinline void vif1SetupTransfer() +{ + tDMA_TAG *ptag; + + switch (vif1.dmamode) + { + case VIF_NORMAL_TO_MEM_MODE: + case VIF_NORMAL_FROM_MEM_MODE: + vif1.inprogress = 1; + vif1.done = true; + g_vifCycles = 2; + break; + + case VIF_CHAIN_MODE: + ptag = dmaGetAddr(vif1ch->tadr); //Set memory pointer to TADR + + if (!(vif1ch->transfer("Vif1 Tag", ptag))) return; + + vif1ch->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("VIF1 Tag %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx\n", + ptag[1]._u32, ptag[0]._u32, vif1ch->qwc, ptag->ID, vif1ch->madr, vif1ch->tadr); + + if (!vif1.done && ((dmacRegs->ctrl.STD == STD_VIF1) && (ptag->ID == TAG_REFS))) // STD == VIF1 + { + // there are still bugs, need to also check if gif->madr +16*qwc >= stadr, if not, stall + if ((vif1ch->madr + vif1ch->qwc * 16) >= dmacRegs->stadr.ADDR) + { + // stalled + hwDmacIrq(DMAC_STALL_SIS); + return; + } + } + + vif1.inprogress = 1; + + if (vif1ch->chcr.TTE) + { + bool ret; + + if (vif1.vifstalled) + ret = VIF1transfer((u32*)ptag + (2 + vif1.irqoffset), 2 - vif1.irqoffset, true); //Transfer Tag on stall + else + ret = VIF1transfer((u32*)ptag + 2, 2, true); //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 + } + } + + vif1.irqoffset = 0; + vif1.done |= hwDmacSrcChainWithStack(vif1ch, ptag->ID); + + //Check TIE bit of CHCR and IRQ bit of tag + if (vif1ch->chcr.TIE && ptag->IRQ) + { + VIF_LOG("dmaIrq Set"); + + //End Transfer + vif1.done = true; + return; + } + break; + } +} + +__forceinline void vif1Interrupt() +{ + VIF_LOG("vif1Interrupt: %8.8x", cpuRegs.cycle); + + g_vifCycles = 0; + + if (schedulepath3msk) Vif1MskPath3(); + + if ((vif1Regs->stat.VGW)) + { + if (gif->chcr.STR) + { + CPU_INT(1, gif->qwc * BIAS); + return; + } + else + { + vif1Regs->stat.VGW = false; + } + } + + if (!(vif1ch->chcr.STR)) Console.WriteLn("Vif1 running when CHCR == %x", vif1ch->chcr._u32); + + if (vif1.irq && vif1.tag.size == 0) + { + vif1Regs->stat.INT = true; + hwIntcIrq(VIF1intc); + --vif1.irq; + if (vif1Regs->stat.test(VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS)) + { + 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(13, vif1ch->qwc * BIAS); + } + } + + if (vif1.inprogress & 0x1) + { + _VIF1chain(); + CPU_INT(1, /*g_vifCycles*/ VifCycleVoodoo); + return; + } + + if (!vif1.done) + { + + if (!(dmacRegs->ctrl.DMAE)) + { + Console.WriteLn("vif1 dma masked"); + return; + } + + if ((vif1.inprogress & 0x1) == 0) vif1SetupTransfer(); + + CPU_INT(1, /*g_vifCycles*/ VifCycleVoodoo); + return; + } + + if (vif1.vifstalled && vif1.irq) + { + CPU_INT(1, 0); + return; //Dont want to end if vif is stalled. + } +#ifdef PCSX2_DEVBUILD + if (vif1ch->qwc > 0) Console.WriteLn("VIF1 Ending with %x QWC left"); + 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; + vif1ch->chcr.STR = false; + g_vifCycles = 0; + hwDmacIrq(DMAC_VIF1); + + //Im not totally sure why Path3 Masking makes it want to see stuff in the fifo + //Games effected by setting, Fatal Frame, KH2, Shox, Crash N Burn, GT3/4 possibly + //Im guessing due to the full gs fifo before the reverse? (Refraction) + //Note also this is only the condition for reverse fifo mode, normal direction clears it as normal + if (!vif1Regs->mskpath3 || vif1ch->chcr.DIR) vif1Regs->stat.FQC = 0; +} + +void dmaVIF1() +{ + VIF_LOG("dmaVIF1 chcr = %lx, madr = %lx, qwc = %lx\n" + " tadr = %lx, asr0 = %lx, asr1 = %lx", + vif1ch->chcr._u32, vif1ch->madr, vif1ch->qwc, + vif1ch->tadr, vif1ch->asr0, vif1ch->asr1); + + g_vifCycles = 0; + vif1.inprogress = 0; + + if (dmacRegs->ctrl.MFD == MFD_VIF1) // VIF MFIFO + { + //Console.WriteLn("VIFMFIFO\n"); + // Test changed because the Final Fantasy 12 opening somehow has the tag in *Undefined* mode, which is not in the documentation that I saw. + if (vif1ch->chcr.MOD == NORMAL_MODE) Console.WriteLn("MFIFO mode is normal (which isn't normal here)! %x", vif1ch->chcr._u32); + vifMFIFOInterrupt(); + return; + } + +#ifdef PCSX2_DEVBUILD + if (dmacRegs->ctrl.STD == STD_VIF1) + { + //DevCon.WriteLn("VIF Stall Control Source = %x, Drain = %x", (psHu32(0xe000) >> 4) & 0x3, (psHu32(0xe000) >> 6) & 0x3); + } +#endif + + if ((vif1ch->chcr.MOD == NORMAL_MODE) || vif1ch->qwc > 0) // Normal Mode + { + + if (dmacRegs->ctrl.STD == STD_VIF1) + Console.WriteLn("DMA Stall Control on VIF1 normal"); + + if (vif1ch->chcr.DIR) // to Memory + vif1.dmamode = VIF_NORMAL_TO_MEM_MODE; + else + vif1.dmamode = VIF_NORMAL_FROM_MEM_MODE; + } + else + { + vif1.dmamode = VIF_CHAIN_MODE; + } + + if (vif1.dmamode != VIF_NORMAL_FROM_MEM_MODE) + vif1Regs->stat.FQC = 0x10; + else + vif1Regs->stat.FQC = min((u16)0x10, vif1ch->qwc); + + // Chain Mode + vif1.done = false; + vif1Interrupt(); +} + +void vif1Write32(u32 mem, u32 value) +{ + switch (mem) + { + case VIF1_MARK: + VIF_LOG("VIF1_MARK write32 0x%8.8x", value); + + /* Clear mark flag in VIF1_STAT and set mark with 'value' */ + vif1Regs->stat.MRK = false; + vif1Regs->mark = value; + break; + + case VIF1_FBRST: // FBRST + VIF_LOG("VIF1_FBRST write32 0x%8.8x", value); + + if (FBRST(value).RST) // Reset Vif. + { + memzero(vif1); + cpuRegs.interrupt &= ~((1 << 1) | (1 << 10)); //Stop all vif1 DMA's + vif1ch->qwc = 0; //? + psHu64(VIF1_FIFO) = 0; + psHu64(VIF1_FIFO + 8) = 0; + vif1.done = true; + + if(vif1Regs->mskpath3) + { + vif1Regs->mskpath3 = 0; + gifRegs->stat.IMT = false; + if (gif->chcr.STR) CPU_INT(2, 4); + } + + vif1Regs->err.reset(); + vif1.inprogress = 0; + 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); + } + + if (FBRST(value).FBK) // Forcebreak Vif. + { + /* I guess we should stop the VIF dma here, but not 100% sure (linuz) */ + vif1Regs->stat.VFS = true; + vif1Regs->stat.VPS = VPS_IDLE; + cpuRegs.interrupt &= ~((1 << 1) | (1 << 10)); //Stop all vif1 DMA's + vif1.vifstalled = true; + Console.WriteLn("vif1 force break"); + } + + if (FBRST(value).STP) // Stop Vif. + { + // Not completely sure about this, can't remember what game used this, but 'draining' the VIF helped it, instead of + // just stoppin the VIF (linuz). + vif1Regs->stat.VSS = true; + vif1Regs->stat.VPS = VPS_IDLE; + cpuRegs.interrupt &= ~((1 << 1) | (1 << 10)); //Stop all vif1 DMA's + vif1.vifstalled = true; + } + + if (FBRST(value).STC) // Cancel Vif Stall. + { + bool cancel = false; + + /* Cancel stall, first check if there is a stall to cancel, and then clear VIF1_STAT VSS|VFS|VIS|INT|ER0|ER1 bits */ + if (vif1Regs->stat.test(VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS)) + { + cancel = true; + } + + vif1Regs->stat.clear_flags(VIF1_STAT_VSS | VIF1_STAT_VFS | VIF1_STAT_VIS | + VIF1_STAT_INT | VIF1_STAT_ER0 | VIF1_STAT_ER1); + + if (cancel) + { + if (vif1.vifstalled) + { + g_vifCycles = 0; + // loop necessary for spiderman + switch(dmacRegs->ctrl.MFD) + { + case MFD_VIF1: + //Console.WriteLn("MFIFO Stall"); + CPU_INT(10, vif1ch->qwc * BIAS); + break; + + case NO_MFD: + case MFD_RESERVED: + case MFD_GIF: // Wonder if this should be with VIF? + // Gets the timing right - Flatout + CPU_INT(1, vif1ch->qwc * BIAS); + break; + } + + vif1ch->chcr.STR = true; + } + } + } + break; + + case VIF1_ERR: // ERR + VIF_LOG("VIF1_ERR write32 0x%8.8x", value); + + /* Set VIF1_ERR with 'value' */ + vif1Regs->err.write(value); + break; + + case VIF1_STAT: // STAT + VIF_LOG("VIF1_STAT write32 0x%8.8x", value); + +#ifdef PCSX2_DEVBUILD + /* Only FDR bit is writable, so mask the rest */ + if ((vif1Regs->stat.FDR) ^ ((tVIF_STAT&)value).FDR) + { + // different so can't be stalled + if (vif1Regs->stat.test(VIF1_STAT_INT | VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS)) + { + DevCon.WriteLn("changing dir when vif1 fifo stalled"); + } + } +#endif + + vif1Regs->stat.FDR = VIF_STAT(value).FDR; + + if (vif1Regs->stat.FDR) // Vif transferring to memory. + { + // Hack but it checks this is true before transfer? (fatal frame) + vif1Regs->stat.FQC = 0x1; + } + else // Memory transferring to Vif. + { + vif1ch->qwc = 0; + vif1.vifstalled = false; + vif1.done = true; + vif1Regs->stat.FQC = 0; + } + break; + + case VIF1_MODE: + vif1Regs->mode = value; + break; + + case VIF1_R0: + case VIF1_R1: + case VIF1_R2: + case VIF1_R3: + pxAssume((mem&0xf) == 0); + g_vifmask.Row1[(mem>>4) & 3] = value; + break; + + case VIF1_C0: + case VIF1_C1: + case VIF1_C2: + case VIF1_C3: + pxAssume((mem&0xf) == 0); + g_vifmask.Col1[(mem>>4) & 3] = value; + break; + + default: + Console.WriteLn("Unknown Vif1 write to %x", mem); + psHu32(mem) = value; + break; + } + + /* Other registers are read-only so do nothing for them */ +} diff --git a/pcsx2/Vif1_MFIFO.cpp b/pcsx2/Vif1_MFIFO.cpp new file mode 100644 index 0000000000..23e2bf4c97 --- /dev/null +++ b/pcsx2/Vif1_MFIFO.cpp @@ -0,0 +1,305 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2009 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#include "PrecompiledHeader.h" +#include "Common.h" +#include "Vif.h" +#include "Vif_Dma.h" + +VIFregisters *vifRegs; +vifStruct *vif; +u16 vifqwc = 0; +int g_vifCycles = 0; + +__aligned16 VifMaskTypes g_vifmask; + +extern int g_vifCycles; + +static __forceinline bool mfifoVIF1rbTransfer() +{ + u32 maddr = dmacRegs->rbor.ADDR; + u32 msize = dmacRegs->rbor.ADDR + dmacRegs->rbsr.RMSK + 16; + u16 mfifoqwc = std::min(vif1ch->qwc, vifqwc); + u32 *src; + bool ret; + + /* Check if the transfer should wrap around the ring buffer */ + if ((vif1ch->madr + (mfifoqwc << 4)) > (msize)) + { + int s1 = ((msize) - vif1ch->madr) >> 2; + + SPR_LOG("Split MFIFO"); + + /* it does, so first copy 's1' bytes from 'addr' to 'data' */ + src = (u32*)PSM(vif1ch->madr); + if (src == NULL) return false; + + if (vif1.vifstalled) + ret = VIF1transfer(src + vif1.irqoffset, s1 - vif1.irqoffset, false); + else + ret = VIF1transfer(src, s1, false); + + if (ret) + { + /* and second copy 's2' bytes from 'maddr' to '&data[s1]' */ + vif1ch->madr = maddr; + + src = (u32*)PSM(maddr); + if (src == NULL) return false; + VIF1transfer(src, ((mfifoqwc << 2) - s1), false); + } + } + else + { + SPR_LOG("Direct MFIFO"); + + /* it doesn't, so just transfer 'qwc*4' words */ + src = (u32*)PSM(vif1ch->madr); + if (src == NULL) return false; + + if (vif1.vifstalled) + ret = VIF1transfer(src + vif1.irqoffset, mfifoqwc * 4 - vif1.irqoffset, false); + else + ret = VIF1transfer(src, mfifoqwc << 2, false); + } + return ret; +} + +static __forceinline bool mfifo_VIF1chain() +{ + bool ret; + + /* Is QWC = 0? if so there is nothing to transfer */ + if ((vif1ch->qwc == 0) && (!vif1.vifstalled)) + { + vif1.inprogress &= ~1; + return true; + } + + if (vif1ch->madr >= dmacRegs->rbor.ADDR && + vif1ch->madr <= (dmacRegs->rbor.ADDR + dmacRegs->rbsr.RMSK)) + { + u16 startqwc = vif1ch->qwc; + ret = mfifoVIF1rbTransfer(); + vifqwc -= startqwc - vif1ch->qwc; + } + else + { + tDMA_TAG *pMem = dmaGetAddr(vif1ch->madr); + SPR_LOG("Non-MFIFO Location"); + + if (pMem == NULL) return false; + + if (vif1.vifstalled) + ret = VIF1transfer((u32*)pMem + vif1.irqoffset, vif1ch->qwc * 4 - vif1.irqoffset, false); + else + ret = VIF1transfer((u32*)pMem, vif1ch->qwc << 2, false); + } + return ret; +} + +static u32 qwctag(u32 mask) +{ + return (dmacRegs->rbor.ADDR + (mask & dmacRegs->rbsr.RMSK)); +} + +void mfifoVIF1transfer(int qwc) +{ + tDMA_TAG *ptag; + + g_vifCycles = 0; + + if (qwc > 0) + { + vifqwc += qwc; + SPR_LOG("Added %x qw to mfifo, total now %x - Vif CHCR %x Stalled %x done %x", qwc, vifqwc, vif1ch->chcr._u32, vif1.vifstalled, vif1.done); + if (vif1.inprogress & 0x10) + { + if (vif1ch->madr >= dmacRegs->rbor.ADDR && vif1ch->madr <= (dmacRegs->rbor.ADDR + dmacRegs->rbsr.RMSK)) + CPU_INT(10, 0); + else + CPU_INT(10, vif1ch->qwc * BIAS); + + vif1Regs->stat.FQC = 0x10; // FQC=16 + } + vif1.inprogress &= ~0x10; + + return; + } + + if (vif1ch->qwc == 0 && vifqwc > 0) + { + ptag = dmaGetAddr(vif1ch->tadr); + + if (vif1ch->chcr.TTE) + { + bool ret; + + if (vif1.stallontag) + ret = VIF1transfer((u32*)ptag + (2 + vif1.irqoffset), 2 - vif1.irqoffset, true); //Transfer Tag on Stall + else + ret = VIF1transfer((u32*)ptag + 2, 2, true); //Transfer Tag + + if (!(ret)) + { + VIF_LOG("MFIFO Stall on tag"); + vif1.stallontag = true; + return; //IRQ set by VIFTransfer + } + } + + vif1ch->unsafeTransfer(ptag); + + vif1ch->madr = ptag[1]._u32; + vifqwc--; + + SPR_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx mfifo qwc = %x spr0 madr = %x", + ptag[1]._u32, ptag[0]._u32, vif1ch->qwc, ptag->ID, vif1ch->madr, vif1ch->tadr, vifqwc, spr0->madr); + + switch (ptag->ID) + { + case TAG_REFE: // Refe - Transfer Packet According to ADDR field + vif1ch->tadr = qwctag(vif1ch->tadr + 16); + vif1.done = true; //End Transfer + break; + + case TAG_CNT: // CNT - Transfer QWC following the tag. + vif1ch->madr = qwctag(vif1ch->tadr + 16); //Set MADR to QW after Tag + vif1ch->tadr = qwctag(vif1ch->madr + (vif1ch->qwc << 4)); //Set TADR to QW following the data + vif1.done = false; + break; + + case TAG_NEXT: // Next - Transfer QWC following tag. TADR = ADDR + { + int temp = vif1ch->madr; //Temporarily Store ADDR + vif1ch->madr = qwctag(vif1ch->tadr + 16); //Set MADR to QW following the tag + vif1ch->tadr = temp; //Copy temporarily stored ADDR to Tag + if ((temp & dmacRegs->rbsr.RMSK) != dmacRegs->rbor.ADDR) Console.WriteLn("Next tag = %x outside ring %x size %x", temp, psHu32(DMAC_RBOR), psHu32(DMAC_RBSR)); + vif1.done = false; + break; + } + + case TAG_REF: // Ref - Transfer QWC from ADDR field + case TAG_REFS: // Refs - Transfer QWC from ADDR field (Stall Control) + vif1ch->tadr = qwctag(vif1ch->tadr + 16); //Set TADR to next tag + vif1.done = false; + break; + + case TAG_END: // End - Transfer QWC following the tag + vif1ch->madr = qwctag(vif1ch->tadr + 16); //Set MADR to data following the tag + vif1ch->tadr = qwctag(vif1ch->madr + (vif1ch->qwc << 4)); //Set TADR to QW following the data + vif1.done = true; //End Transfer + break; + } + + if (vif1ch->chcr.TIE && ptag->IRQ) + { + VIF_LOG("dmaIrq Set"); + vif1.done = true; + } + } + + vif1.inprogress |= 1; + + SPR_LOG("mfifoVIF1transfer end %x madr %x, tadr %x vifqwc %x", vif1ch->chcr._u32, vif1ch->madr, vif1ch->tadr, vifqwc); +} + +void vifMFIFOInterrupt() +{ + g_vifCycles = 0; + + if (schedulepath3msk) Vif1MskPath3(); + + if ((vif1Regs->stat.VGW)) + { + if (gif->chcr.STR) + { + CPU_INT(10, 16); + return; + } + else + { + vif1Regs->stat.VGW = false; + } + + } + + if ((spr0->chcr.STR) && (spr0->qwc == 0)) + { + spr0->chcr.STR = false; + hwDmacIrq(DMAC_FROM_SPR); + } + + if (vif1.irq && vif1.tag.size == 0) + { + vif1Regs->stat.INT = true; + hwIntcIrq(INTC_VIF1); + --vif1.irq; + + if (vif1Regs->stat.test(VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS)) + { + vif1Regs->stat.FQC = 0; // FQC=0 + vif1ch->chcr.STR = false; + return; + } + } + + if (vif1.done == false || vif1ch->qwc) + { + switch(vif1.inprogress & 1) + { + case 0: //Set up transfer + if (vif1ch->tadr == spr0->madr) + { + // Console.WriteLn("Empty 1"); + vifqwc = 0; + vif1.inprogress |= 0x10; + vif1Regs->stat.FQC = 0; + hwDmacIrq(DMAC_MFIFO_EMPTY); + return; + } + + mfifoVIF1transfer(0); + if ((vif1ch->madr >= dmacRegs->rbor.ADDR) && (vif1ch->madr <= (dmacRegs->rbor.ADDR + dmacRegs->rbsr.RMSK))) + CPU_INT(10, 0); + else + CPU_INT(10, vif1ch->qwc * BIAS); + + return; + + case 1: //Transfer data + mfifo_VIF1chain(); + CPU_INT(10, 0); + return; + } + return; + } + + /*if (vifqwc <= 0) + { + //Console.WriteLn("Empty 2"); + //vif1.inprogress |= 0x10; + vif1Regs->stat.FQC = 0; // FQC=0 + hwDmacIrq(DMAC_MFIFO_EMPTY); + }*/ + + vif1.done = 1; + g_vifCycles = 0; + vif1ch->chcr.STR = false; + hwDmacIrq(DMAC_VIF1); + VIF_LOG("vif mfifo dma end"); + + vif1Regs->stat.FQC = 0; +} diff --git a/pcsx2/VifDma_internal.h b/pcsx2/VifDma_internal.h deleted file mode 100644 index 4e7157cb19..0000000000 --- a/pcsx2/VifDma_internal.h +++ /dev/null @@ -1,20 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2009 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#pragma once - -#include "VifDma.h" - - diff --git a/pcsx2/VifDma.cpp b/pcsx2/Vif_Commands.cpp similarity index 78% rename from pcsx2/VifDma.cpp rename to pcsx2/Vif_Commands.cpp index e20c720f93..09c3dc0961 100644 --- a/pcsx2/VifDma.cpp +++ b/pcsx2/Vif_Commands.cpp @@ -1,64 +1,54 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2009 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "PrecompiledHeader.h" -#include "Common.h" - -#include "VifDma.h" -#include "VUmicro.h" - -int g_vifCycles = 0; - -template void vuExecMicro<0>(u32 addr); -template void vuExecMicro<1>(u32 addr); -template void vuExecMicro(u32 addr) -{ - VURegs * VU; - - if (VIFdmanum == 0) { - VU = &VU0; - vif0FLUSH(); - } - else { - VU = &VU1; - vif1FLUSH(); - } - - if (VU->vifRegs->itops > (VIFdmanum ? 0x3ffu : 0xffu)) - Console.WriteLn("VIF%d ITOP overrun! %x", VIFdmanum, VU->vifRegs->itops); - - VU->vifRegs->itop = VU->vifRegs->itops; - - if (VIFdmanum == 1) - { - /* in case we're handling a VIF1 execMicro, set the top with the tops value */ - VU->vifRegs->top = VU->vifRegs->tops & 0x3ff; - - /* is DBF flag set in VIF_STAT? */ - if (VU->vifRegs->stat.DBF) { - /* it is, so set tops with base, and clear the stat DBF flag */ - VU->vifRegs->tops = VU->vifRegs->base; - VU->vifRegs->stat.DBF = false; - } - else { - /* it is not, so set tops with base + offset, and set stat DBF flag */ - VU->vifRegs->tops = VU->vifRegs->base + VU->vifRegs->ofst; - VU->vifRegs->stat.DBF = true; - } - } - - if (!VIFdmanum) vu0ExecMicro(addr); - else vu1ExecMicro(addr); -} +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2009 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#include "PrecompiledHeader.h" +#include "Common.h" +#include "Vif_Dma.h" +#include "VUmicro.h" + +template void vuExecMicro<0>(u32 addr); +template void vuExecMicro<1>(u32 addr); +template void vuExecMicro(u32 addr) +{ + VURegs * VU; + if (!VIFdmanum) { VU = &VU0; vif0FLUSH(); } + else { VU = &VU1; vif1FLUSH(); } + + if (VU->vifRegs->itops > (VIFdmanum ? 0x3ffu : 0xffu)) + Console.WriteLn("VIF%d ITOP overrun! %x", VIFdmanum, VU->vifRegs->itops); + + VU->vifRegs->itop = VU->vifRegs->itops; + + if (VIFdmanum == 1) + { + // in case we're handling a VIF1 execMicro, set the top with the tops value + VU->vifRegs->top = VU->vifRegs->tops & 0x3ff; + + // is DBF flag set in VIF_STAT? + if (VU->vifRegs->stat.DBF) { + // it is, so set tops with base, and clear the stat DBF flag + VU->vifRegs->tops = VU->vifRegs->base; + VU->vifRegs->stat.DBF = false; + } + else { + // it is not, so set tops with base + offset, and set stat DBF flag + VU->vifRegs->tops = VU->vifRegs->base + VU->vifRegs->ofst; + VU->vifRegs->stat.DBF = true; + } + } + + if (!VIFdmanum) vu0ExecMicro(addr); + else vu1ExecMicro(addr); +} diff --git a/pcsx2/VifDma.h b/pcsx2/Vif_Dma.h similarity index 82% rename from pcsx2/VifDma.h rename to pcsx2/Vif_Dma.h index d82d6d7c86..1c14c8ed2a 100644 --- a/pcsx2/VifDma.h +++ b/pcsx2/Vif_Dma.h @@ -1,84 +1,95 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2009 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#pragma once -#include "Vif_Unpack.h" - -struct vifCode { - u32 addr; - u32 size; - u32 cmd; - u16 wl; - u16 cl; -}; - -// NOTE, if debugging vif stalls, use sega classics, spyro, gt4, and taito -struct vifStruct { - vifCode tag; - int cmd; - int irq; - int cl; - int qwcalign; - u8 usn; - - bool done; - bool vifstalled; - bool stallontag; - - u8 irqoffset; // 32bit offset where next vif code is - u32 savedtag; // need this for backwards compat with save states - u32 vifpacketsize; - u8 inprogress; - u8 dmamode; -}; - -extern vifStruct* vif; -extern vifStruct vif0, vif1; -extern u8 schedulepath3msk; -static const int VifCycleVoodoo = 4; - -extern void vif0Init(); -extern void vif0Interrupt(); -extern void vif0Write32(u32 mem, u32 value); -extern void vif0Reset(); - -extern void vif1Interrupt(); -extern void vif1Init(); -extern void Vif1MskPath3(); -extern void vif1Write32(u32 mem, u32 value); -extern void vif1Reset(); - -__forceinline static int _limit(int a, int max) -{ - return ((a > max) ? max : a); -} - -enum VifModes -{ - VIF_NORMAL_TO_MEM_MODE = 0, - VIF_NORMAL_FROM_MEM_MODE = 1, - VIF_CHAIN_MODE = 2 -}; - -// Generic constants -static const unsigned int VIF0intc = 4; -static const unsigned int VIF1intc = 5; - -extern int g_vifCycles; - -template void vuExecMicro(u32 addr); -extern void vif0FLUSH(); -extern void vif1FLUSH(); - +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2009 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#pragma once +#include "Vif_Unpack.h" + +struct vifCode { + u32 addr; + u32 size; + u32 cmd; + u16 wl; + u16 cl; +}; + +// NOTE, if debugging vif stalls, use sega classics, spyro, gt4, and taito +struct vifStruct { + vifCode tag; + int cmd; + int irq; + int cl; + int qwcalign; + u8 usn; + + bool done; + bool vifstalled; + bool stallontag; + + u8 irqoffset; // 32bit offset where next vif code is + u32 savedtag; // need this for backwards compat with save states + u32 vifpacketsize; + u8 inprogress; + u8 dmamode; +}; + +extern vifStruct* vif; +extern vifStruct vif0, vif1; +extern u8 schedulepath3msk; +static const int VifCycleVoodoo = 4; + +extern void vif0Init(); +extern void vif0Interrupt(); +extern void vif0Write32(u32 mem, u32 value); +extern void vif0Reset(); + +extern void vif1Interrupt(); +extern void vif1Init(); +extern void Vif1MskPath3(); +extern void vif1Write32(u32 mem, u32 value); +extern void vif1Reset(); + +__forceinline static int _limit(int a, int max) +{ + return ((a > max) ? max : a); +} + +enum VifModes +{ + VIF_NORMAL_TO_MEM_MODE = 0, + VIF_NORMAL_FROM_MEM_MODE = 1, + VIF_CHAIN_MODE = 2 +}; + +// Generic constants +static const unsigned int VIF0intc = 4; +static const unsigned int VIF1intc = 5; + +extern int g_vifCycles; + +template void vuExecMicro(u32 addr); +extern void vif0FLUSH(); +extern void vif1FLUSH(); + +//------------------------------------------------------------------ +// newVif SSE-optimized Row/Col Structs +//------------------------------------------------------------------ + +struct VifMaskTypes +{ + u32 Row0[4], Col0[4]; + u32 Row1[4], Col1[4]; +}; + +extern __aligned16 VifMaskTypes g_vifmask; // This struct is used by newVif diff --git a/pcsx2/Vif_Unpack.cpp b/pcsx2/Vif_Unpack.cpp index f66a545aca..f4eb7e9e97 100644 --- a/pcsx2/Vif_Unpack.cpp +++ b/pcsx2/Vif_Unpack.cpp @@ -16,7 +16,7 @@ #include "PrecompiledHeader.h" #include "Common.h" #include "Vif.h" -#include "VifDma.h" +#include "Vif_Dma.h" enum UnpackOffset { OFFSET_X = 0, diff --git a/pcsx2/ps2/GIFpath.cpp b/pcsx2/ps2/GIFpath.cpp index be749e0986..d320fa2739 100644 --- a/pcsx2/ps2/GIFpath.cpp +++ b/pcsx2/ps2/GIFpath.cpp @@ -17,7 +17,7 @@ #include "Common.h" #include "GS.h" #include "Gif.h" -#include "VifDma.h" +#include "Vif_Dma.h" // -------------------------------------------------------------------------------------- // GIFpath -- the GIFtag Parser diff --git a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj index d505395ccb..5720935adc 100644 --- a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj +++ b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj @@ -805,19 +805,31 @@ > + + + + + + > 4, doMask ? wxsFormat( L"0x%08x", _vBlock.mask ).c_str() : L"ignored" diff --git a/pcsx2/x86/newVif_Unpack.cpp b/pcsx2/x86/newVif_Unpack.cpp index 64e81fbd10..247f49aa97 100644 --- a/pcsx2/x86/newVif_Unpack.cpp +++ b/pcsx2/x86/newVif_Unpack.cpp @@ -19,7 +19,7 @@ #include "PrecompiledHeader.h" #include "Common.h" -#include "VifDma.h" +#include "Vif_Dma.h" #include "newVif.h" #include "Vif_Unpack.inl" diff --git a/pcsx2/x86/newVif_UnpackSSE.h b/pcsx2/x86/newVif_UnpackSSE.h index 4da4454a5e..01629630c4 100644 --- a/pcsx2/x86/newVif_UnpackSSE.h +++ b/pcsx2/x86/newVif_UnpackSSE.h @@ -16,7 +16,7 @@ #pragma once #include "Common.h" -#include "VifDma.h" +#include "Vif_Dma.h" #include "newVif.h" #include