diff --git a/pcsx2/Linux/pcsx2.cbp b/pcsx2/Linux/pcsx2.cbp index ad0918cbc6..a15707c10c 100644 --- a/pcsx2/Linux/pcsx2.cbp +++ b/pcsx2/Linux/pcsx2.cbp @@ -258,8 +258,11 @@ + + + diff --git a/pcsx2/Vif.cpp b/pcsx2/Vif.cpp index 65a1e0bd9a..ff0e7e16cd 100644 --- a/pcsx2/Vif.cpp +++ b/pcsx2/Vif.cpp @@ -41,11 +41,6 @@ enum UnpackOffset OFFSET_W = 3 }; -__forceinline static int _limit(int a, int max) -{ - return (a > max) ? max : a; -} - static __forceinline u32 setVifRowRegs(u32 reg, u32 data) { switch (reg) diff --git a/pcsx2/Vif0Dma.cpp b/pcsx2/Vif0Dma.cpp new file mode 100644 index 0000000000..126c040c79 --- /dev/null +++ b/pcsx2/Vif0Dma.cpp @@ -0,0 +1,808 @@ +/* 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 "VifDma_internal.h" +#include "VUmicro.h" +#include "Tags.h" + +__aligned16 u32 g_vif0Masks[64]; +u32 g_vif0HasMask3[4] = {0}; + +extern int (__fastcall *Vif0TransTLB[128])(u32 *data); +extern void (*Vif0CMDTLB[75])(); + +vifStruct vif0; +u32 *vif0ptag; +__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() +{ + for (u32 i = 0; i < 256; ++i) + { + s_maskwrite[i] = ((i & 3) == 3) || ((i & 0xc) == 0xc) || ((i & 0x30) == 0x30) || ((i & 0xc0) == 0xc0); + } + + SetNewMask(g_vif0Masks, g_vif0HasMask3, 0, 0xffffffff); +} + +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 +{ + SetNewMask(g_vif0Masks, g_vif0HasMask3, data[0], vif0Regs->mask); + 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; + assert(vif0.tag.addr < 4); + ret = min(4 - vif0.tag.addr, vif0.vifpacketsize); + assert(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.Notice("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.Notice("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 +{ + int ret; + + FreezeXMMRegs(1); + if (vif0.vifpacketsize < vif0.tag.size) + { + if(vif0Regs->offset != 0 || vif0.cl != 0) + { + ret = vif0.tag.size; + vif0.tag.size -= vif0.vifpacketsize - VIFalign<0>(data, &vif0.tag, vif0.vifpacketsize); + ret = ret - vif0.tag.size; + data += ret; + + if(vif0.vifpacketsize > 0) VIFunpack<0>(data, &vif0.tag, vif0.vifpacketsize - ret); + + ProcessMemSkip<0>((vif0.vifpacketsize - ret) << 2, (vif0.cmd & 0xf)); + vif0.tag.size -= (vif0.vifpacketsize - ret); + FreezeXMMRegs(0); + + return vif0.vifpacketsize; + } + /* size is less that the total size, transfer is 'in pieces' */ + VIFunpack<0>(data, &vif0.tag, vif0.vifpacketsize); + + ProcessMemSkip<0>(vif0.vifpacketsize << 2, (vif0.cmd & 0xf)); + + ret = vif0.vifpacketsize; + vif0.tag.size -= ret; + } + else + { + /* we got all the data, transfer it fully */ + ret = vif0.tag.size; + + //Align data after a split transfer first + if ((vif0Regs->offset != 0) || (vif0.cl != 0)) + { + vif0.tag.size = VIFalign<0>(data, &vif0.tag, vif0.tag.size); + data += ret - vif0.tag.size; + if(vif0.tag.size > 0) VIFunpack<0>(data, &vif0.tag, vif0.tag.size); + } + else + { + VIFunpack<0>(data, &vif0.tag, vif0.tag.size); + } + + vif0.tag.size = 0; + vif0.cmd = 0; + } + + FreezeXMMRegs(0); + return ret; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// 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 = 1; + 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 = 1; + vif0.irq++; + } + vif0.cmd &= ~0x7f; +} + +int VIF0transfer(u32 *data, int size, int 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 = 1; + 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 = 1; + //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 -2; + } + + vif0Regs->stat.VPS = 0; //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 0; +} + +int _VIF0chain() +{ + u32 *pMem; + u32 ret; + + if ((vif0ch->qwc == 0) && !vif0.vifstalled) return 0; + + pMem = (u32*)dmaGetAddr(vif0ch->madr); + if (pMem == NULL) + { + vif0.cmd = 0; + vif0.tag.size = 0; + vif0ch->qwc = 0; + return 0; + } + + if (vif0.vifstalled) + ret = VIF0transfer(pMem + vif0.irqoffset, vif0ch->qwc * 4 - vif0.irqoffset, 0); + else + ret = VIF0transfer(pMem, vif0ch->qwc * 4, 0); + + return ret; +} + +int _chainVIF0() +{ + int id, ret; + + vif0ptag = (u32*)dmaGetAddr(vif0ch->tadr); //Set memory pointer to TADR + + if (!(Tag::Transfer("Vif0 Tag", vif0ch, vif0ptag))) return -1; + + vif0ch->madr = vif0ptag[1]; // MADR = ADDR field + id = Tag::Id(vif0ptag); // ID for DmaChain copied from bit 28 of the tag + 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", + vif0ptag[1], vif0ptag[0], vif0ch->qwc, id, vif0ch->madr, vif0ch->tadr); + + // Transfer dma tag if tte is set + if (vif0ch->chcr.TTE) + { + if (vif0.vifstalled) + ret = VIF0transfer(vif0ptag + (2 + vif0.irqoffset), 2 - vif0.irqoffset, 1); //Transfer Tag on stall + else + ret = VIF0transfer(vif0ptag + 2, 2, 1); //Transfer Tag + + if (ret == -1) return -1; //There has been an error + if (ret == -2) return -2; //IRQ set by VIFTransfer + } + + vif0.done |= hwDmacSrcChainWithStack(vif0ch, id); + + VIF_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx", + vif0ptag[1], vif0ptag[0], vif0ch->qwc, id, vif0ch->madr, vif0ch->tadr); + + ret = _VIF0chain(); //Transfers the data set by the switch + + if (vif0ch->chcr.TIE && Tag::IRQ(vif0ptag)) //Check TIE bit of CHCR and IRQ bit of tag + { + VIF_LOG("dmaIrq Set\n"); + + vif0.done = true; //End Transfer + } + return (vif0.done) ? 1: 0; //Return 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 = 1; + hwIntcIrq(VIF0intc); + --vif0.irq; + + if (vif0Regs->stat.test(VIF0_STAT_VSS | VIF0_STAT_VIS | VIF0_STAT_VFS)) + { + vif0Regs->stat.FQC = 0; // FQC=0 + vif0ch->chcr.STR = 0; + return; + } + + if (vif0ch->qwc > 0 || vif0.irqoffset > 0) + { + if (vif0.stallontag) + _chainVIF0(); + else + _VIF0chain(); + + CPU_INT(0, g_vifCycles); + 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); + 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 = 0; + hwDmacIrq(DMAC_VIF0); + vif0Regs->stat.FQC = 0; // 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() == -2) + { + Console.WriteLn("Stall on normal %x", vif0Regs->stat._u32); + + vif0.vifstalled = true; + return; + } + + vif0.done = true; + CPU_INT(0, g_vifCycles); + 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 = 0; + 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._u32 = 0; + vif0Regs->stat.clear(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 = 1; + vif0Regs->stat.VPS = 0; + 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 = 1; + vif0Regs->stat.VPS = 0; + 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(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 = 1; + 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._u32 = value; + break; + + case VIF0_R0: + case VIF0_R1: + case VIF0_R2: + case VIF0_R3: + assert((mem&0xf) == 0); + g_vifmask.Row0[(mem>>4) & 3] = value; + break; + + case VIF0_C0: + case VIF0_C1: + case VIF0_C2: + case VIF0_C3: + assert((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); + SetNewMask(g_vif0Masks, g_vif0HasMask3, 0, 0xffffffff); + + psHu64(VIF0_FIFO) = 0; + psHu64(VIF0_FIFO + 8) = 0; + + vif0Regs->stat.VPS = 0; + vif0Regs->stat.FQC = 0; + + vif0.done = true; +} + +void SaveStateBase::vif0Freeze() +{ + 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); + Freeze(g_vif0Masks); +} diff --git a/pcsx2/Vif1Dma.cpp b/pcsx2/Vif1Dma.cpp new file mode 100644 index 0000000000..c7c9163713 --- /dev/null +++ b/pcsx2/Vif1Dma.cpp @@ -0,0 +1,1196 @@ +/* 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 "GS.h" +#include "Gif.h" +#include "VifDma.h" +#include "VifDma_internal.h" +#include "VUmicro.h" +#include "Tags.h" + +__aligned16 u32 g_vif1Masks[64]; +u32 g_vif1HasMask3[4] = {0}; + +extern void (*Vif1CMDTLB[82])(); +extern int (__fastcall *Vif1TransTLB[128])(u32 *data); + +Path3Modes Path3progress = STOPPED_MODE; +vifStruct vif1; +static u32 *vif1ptag; + +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() +{ + SetNewMask(g_vif1Masks, g_vif1HasMask3, 0, 0xffffffff); +} + +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); + }*/ + assert(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 +{ + SetNewMask(g_vif1Masks, g_vif1HasMask3, data[0], vif1Regs->mask); + 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; + assert(vif1.tag.addr < 4); + ret = min(4 - vif1.tag.addr, vif1.vifpacketsize); + assert(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.Notice("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.Notice("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 = 1; + return 0; + } + } + + gifRegs->stat.APATH |= GIF_APATH2; + gifRegs->stat.OPH = 1; + + + 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--; + } + } + + FreezeRegs(1); + // copy 16 bytes the fast way: + const u64* src = (u64*)splittransfer[0]; + mtgsThread.PrepDataPacket(GIF_PATH_2, nloop0_packet, 1); + u64* dst = (u64*)mtgsThread.GetDataPacketPtr(); + dst[0] = src[0]; + dst[1] = src[1]; + + mtgsThread.SendDataPacket(); + FreezeRegs(0); + + 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(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 ? + + FreezeRegs(1); + + // Round ret up, just in case it's not 128bit aligned. + const uint count = mtgsThread.PrepDataPacket(GIF_PATH_2, data, (ret + 3) >> 2); + memcpy_fast(mtgsThread.GetDataPacketPtr(), data, count << 4); + mtgsThread.SendDataPacket(); + + FreezeRegs(0); + + return ret; +} + +static int __fastcall Vif1TransUnpack(u32 *data) +{ + FreezeXMMRegs(1); + + if (vif1.vifpacketsize < vif1.tag.size) + { + int ret = vif1.tag.size; + /* size is less that the total size, transfer is 'in pieces' */ + if (vif1Regs->offset != 0 || vif1.cl != 0) + { + vif1.tag.size -= vif1.vifpacketsize - VIFalign<1>(data, &vif1.tag, vif1.vifpacketsize); + ret = ret - vif1.tag.size; + data += ret; + if ((vif1.vifpacketsize - ret) > 0) VIFunpack<1>(data, &vif1.tag, vif1.vifpacketsize - ret); + ProcessMemSkip<1>((vif1.vifpacketsize - ret) << 2, (vif1.cmd & 0xf)); + vif1.tag.size -= (vif1.vifpacketsize - ret); + } + else + { + VIFunpack<1>(data, &vif1.tag, vif1.vifpacketsize); + + ProcessMemSkip<1>(vif1.vifpacketsize << 2, (vif1.cmd & 0xf)); + vif1.tag.size -= vif1.vifpacketsize; + } + + FreezeXMMRegs(0); + return vif1.vifpacketsize; + } + else + { + int ret = vif1.tag.size; + + if (vif1Regs->offset != 0 || vif1.cl != 0) + { + vif1.tag.size = VIFalign<1>(data, &vif1.tag, vif1.tag.size); + data += ret - vif1.tag.size; + if (vif1.tag.size > 0) VIFunpack<1>(data, &vif1.tag, vif1.tag.size); + } + else + { + /* we got all the data, transfer it fully */ + VIFunpack<1>(data, &vif1.tag, vif1.tag.size); + } + + vif1.tag.size = 0; + vif1.cmd = 0; + FreezeXMMRegs(0); + return ret; + } + +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// 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 = 0; + 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 = 1; + } + else + { + //Let the Gif know it can transfer again (making sure any vif stall isnt unset prematurely) + Path3progress = TRANSFER_MODE; + gifRegs->stat.IMT = 0; + 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 = 1; + 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 = 1; + 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 = 1; + 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 +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +int VIF1transfer(u32 *data, int size, int 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 = 1; + 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 = 1; // 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 -2; + + 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 -2; + } + + vif1Regs->stat.VPS = 0; //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 ? -2 : 0; +} + +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 = 1; //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. + + FreezeXMMRegs(1); + + if (GSreadFIFO2 == NULL) + { + for (size = vif1ch->qwc; size > 0; --size) + { + if (size > 1) + { + mtgsWaitGS(); + GSreadFIFO((u64*)&PS2MEM_HW[0x5000]); + } + pMem[0] = psHu64(VIF1_FIFO); + pMem[1] = psHu64(VIF1_FIFO + 8); + pMem += 2; + } + } + else + { + mtgsWaitGS(); + GSreadFIFO2(pMem, vif1ch->qwc); + + // set incase read + psHu64(VIF1_FIFO) = pMem[2*vif1ch->qwc-2]; + psHu64(VIF1_FIFO + 8) = pMem[2*vif1ch->qwc-1]; + } + + FreezeXMMRegs(0); + + g_vifCycles += vif1ch->qwc * 2; + vif1ch->madr += vif1ch->qwc * 16; // mgs3 scene changes + vif1ch->qwc = 0; +} + +int _VIF1chain() +{ + u32 *pMem; + u32 ret; + + if (vif1ch->qwc == 0) + { + vif1.inprogress = 0; + return 0; + } + + if (vif1.dmamode == VIF_NORMAL_FROM_MEM_MODE) + { + vif1TransferFromMemory(); + vif1.inprogress = 0; + return 0; + } + + pMem = (u32*)dmaGetAddr(vif1ch->madr); + if (pMem == NULL) + { + vif1.cmd = 0; + vif1.tag.size = 0; + vif1ch->qwc = 0; + return 0; + } + + VIF_LOG("VIF1chain size=%d, madr=%lx, tadr=%lx", + vif1ch->qwc, vif1ch->madr, vif1ch->tadr); + + if (vif1.vifstalled) + ret = VIF1transfer(pMem + vif1.irqoffset, vif1ch->qwc * 4 - vif1.irqoffset, 0); + else + ret = VIF1transfer(pMem, vif1ch->qwc * 4, 0); + + return ret; +} + +bool _chainVIF1() +{ + return vif1.done; // Return Done +} + +__forceinline void vif1SetupTransfer() +{ + 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: + int id; + int ret; + + vif1ptag = (u32*)dmaGetAddr(vif1ch->tadr); //Set memory pointer to TADR + + if (!(Tag::Transfer("Vif1 Tag", vif1ch, vif1ptag))) return; + + vif1ch->madr = vif1ptag[1]; //MADR = ADDR field + g_vifCycles += 1; // Add 1 g_vifCycles from the QW read for the tag + id = Tag::Id(vif1ptag); //ID for DmaChain copied from bit 28 of 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", + vif1ptag[1], vif1ptag[0], vif1ch->qwc, id, vif1ch->madr, vif1ch->tadr); + + if (!vif1.done && ((dmacRegs->ctrl.STD == STD_VIF1) && (id == 4))) // 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) + { + + if (vif1.vifstalled) + ret = VIF1transfer(vif1ptag + (2 + vif1.irqoffset), 2 - vif1.irqoffset, 1); //Transfer Tag on stall + else + ret = VIF1transfer(vif1ptag + 2, 2, 1); //Transfer Tag + + if (ret < 0 && 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, id); + + //Check TIE bit of CHCR and IRQ bit of tag + if (vif1ch->chcr.TIE && (Tag::IRQ(vif1ptag))) + { + 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 = 0; + } + } + + if (!(vif1ch->chcr.STR)) Console.WriteLn("Vif1 running when CHCR == %x", vif1ch->chcr._u32); + + if (vif1.irq && vif1.tag.size == 0) + { + vif1Regs->stat.INT = 1; + 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 = 0; + 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); + 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); + 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 = 0; //Vif goes idle as the stall happened between commands; + vif1ch->chcr.STR = 0; + 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, 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); + 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.set(min((u16)16, vif1ch->qwc) << 24); + + // 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 = 0; + vif1Regs->mark = value; + break; + + case VIF1_FBRST: // FBRST + VIF_LOG("VIF1_FBRST write32 0x%8.8x", value); + + if (value & 0x1) // 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 = 0; + if (gif->chcr.STR) CPU_INT(2, 4); + } + + vif1Regs->err._u32 = 0; + vif1.inprogress = 0; + vif1Regs->stat.clear(VIF1_STAT_FQC | VIF1_STAT_FDR | VIF1_STAT_INT | VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS | VIF1_STAT_VPS); // FQC=0 + } + + if (value & 0x2) // Forcebreak Vif. + { + /* I guess we should stop the VIF dma here, but not 100% sure (linuz) */ + vif1Regs->stat.VFS = 1; + vif1Regs->stat.VPS = 0; + cpuRegs.interrupt &= ~((1 << 1) | (1 << 10)); //Stop all vif1 DMA's + vif1.vifstalled = true; + Console.WriteLn("vif1 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). + vif1Regs->stat.VSS = 1; + vif1Regs->stat.VPS = 0; + cpuRegs.interrupt &= ~((1 << 1) | (1 << 10)); //Stop all vif1 DMA's + vif1.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 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(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 = 1; + } + } + } + break; + + case VIF1_ERR: // ERR + VIF_LOG("VIF1_ERR write32 0x%8.8x", value); + + /* Set VIF1_ERR with 'value' */ + vif1Regs->err._u32 = 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) ^(value & VIF1_STAT_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._u32 = (vif1Regs->stat.test(~VIF1_STAT_FDR)) | (value & VIF1_STAT_FDR); + if (vif1Regs->stat.FDR) + { + vif1Regs->stat.FQC = 1; // FQC=1 - hack but it checks this is true before transfer? (fatal frame) + } + else + { + vif1ch->qwc = 0; + vif1.vifstalled = false; + vif1.done = true; + vif1Regs->stat.FQC = 0; // FQC=0 + } + break; + + case VIF1_MODE: // MODE + vif1Regs->mode = value; + break; + + case VIF1_R0: + case VIF1_R1: + case VIF1_R2: + case VIF1_R3: + assert((mem&0xf) == 0); + g_vifmask.Row1[(mem>>4) & 3] = value; + break; + + case VIF1_C0: + case VIF1_C1: + case VIF1_C2: + case VIF1_C3: + assert((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); + SetNewMask(g_vif1Masks, g_vif1HasMask3, 0, 0xffffffff); + + psHu64(VIF1_FIFO) = 0; + psHu64(VIF1_FIFO + 8) = 0; + + vif1Regs->stat.VPS = 0; + vif1Regs->stat.FQC = 0; // FQC=0 + + vif1.done = true; + cpuRegs.interrupt &= ~((1 << 1) | (1 << 10)); //Stop all vif1 DMA's +} + +void SaveStateBase::vif1Freeze() +{ + Freeze(vif1); + + Freeze(g_vif1HasMask3); + Freeze(g_vif1Masks); +} diff --git a/pcsx2/VifDma.cpp b/pcsx2/VifDma.cpp index 315ed7b21e..2523271f3c 100644 --- a/pcsx2/VifDma.cpp +++ b/pcsx2/VifDma.cpp @@ -16,10 +16,8 @@ #include "PrecompiledHeader.h" #include "Common.h" -#include "GS.h" -#include "Gif.h" -#include "Vif.h" #include "VifDma.h" +#include "VifDma_internal.h" #include "VUmicro.h" #include "Tags.h" @@ -39,46 +37,9 @@ extern "C" extern vifStruct *vif; -vifStruct vif0, vif1; - -static __aligned16 u32 g_vif1Masks[64]; -static __aligned16 u32 g_vif0Masks[64]; -u32 g_vif1HasMask3[4] = {0}, g_vif0HasMask3[4] = {0}; - -// Generic constants -static const unsigned int VIF0intc = 4; -static const unsigned int VIF1intc = 5; -static const unsigned int VIF0dmanum = 0; -static const unsigned int VIF1dmanum = 1; - int g_vifCycles = 0; -Path3Modes Path3progress = STOPPED_MODE; - -static __aligned16 u32 splittransfer[4]; -u32 splitptr = 0; - -typedef void (__fastcall *UNPACKFUNCTYPE)(u32 *dest, u32 *data, int size); -typedef int (*UNPACKPARTFUNCTYPESSE)(u32 *dest, u32 *data, int size); -extern void (*Vif1CMDTLB[82])(); -extern void (*Vif0CMDTLB[75])(); -extern int (__fastcall *Vif1TransTLB[128])(u32 *data); -extern int (__fastcall *Vif0TransTLB[128])(u32 *data); - -u32 *vif0ptag, *vif1ptag; u8 s_maskwrite[256]; -struct VIFUnpackFuncTable -{ - UNPACKFUNCTYPE funcU; - UNPACKFUNCTYPE funcS; - - u32 bsize; // currently unused - u32 dsize; // byte size of one channel - u32 gsize; // size of data in bytes used for each write cycle - u32 qsize; // used for unpack parts, num of vectors that - // will be decompressed from data for 1 cycle -}; - /* block size; data size; group size; qword size; */ #define _UNPACK_TABLE32(name, bsize, dsize, gsize, qsize) \ { UNPACK_##name, UNPACK_##name, \ @@ -89,7 +50,7 @@ struct VIFUnpackFuncTable bsize, dsize, gsize, qsize }, // Main table for function unpacking -static const VIFUnpackFuncTable VIFfuncTable[16] = +const VIFUnpackFuncTable VIFfuncTable[16] = { _UNPACK_TABLE32(S_32, 1, 4, 4, 4) // 0x0 - S-32 _UNPACK_TABLE(S_16, 2, 2, 2, 4) // 0x1 - S-16 @@ -203,46 +164,13 @@ static const VIFSSEUnpackTable VIFfuncTableSSE[16] = { _UNPACK_TABLE_SSE(V4_5, u), _UNPACK_TABLE_SSE(V4_5, u) }, }; -__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; -} - -__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 vifDmaInit() { } -__forceinline static int _limit(int a, int max) -{ - return (a > max ? max : a); -} - -static void ProcessMemSkip(int size, unsigned int unpackType, const unsigned int VIFdmanum) +template void ProcessMemSkip<0>(u32 size, u32 unpackType); +template void ProcessMemSkip<1>(u32 size, u32 unpackType); +template void ProcessMemSkip(u32 size, u32 unpackType) { const VIFUnpackFuncTable *unpack; @@ -307,7 +235,7 @@ static void ProcessMemSkip(int size, unsigned int unpackType, const unsigned int break; } - //Append any skips in to the equasion + //Append any skips in to the equation if (vifRegs->cycle.cl > vifRegs->cycle.wl) { @@ -323,13 +251,15 @@ static void ProcessMemSkip(int size, unsigned int unpackType, const unsigned int vif->tag.addr = (vif->tag.addr & ~0xf) + (vifRegs->offset * 4); } - if (vif->tag.addr >= (u32)(VIFdmanum ? 0x4000 : 0x1000)) + if (vif->tag.addr >= (u32)vif_size(VIFdmanum)) { - vif->tag.addr &= (u32)(VIFdmanum ? 0x3fff : 0xfff); + vif->tag.addr &= (u32)(vif_size(VIFdmanum) - 1); } } -static int VIFalign(u32 *data, vifCode *v, unsigned int size, const unsigned int VIFdmanum) +template u32 VIFalign<0>(u32 *data, vifCode *v, u32 size); +template u32 VIFalign<1>(u32 *data, vifCode *v, u32 size); +template u32 VIFalign(u32 *data, vifCode *v, u32 size) { u32 *dest; u32 unpackType; @@ -339,7 +269,7 @@ static int VIFalign(u32 *data, vifCode *v, unsigned int size, const unsigned int u8 *cdata = (u8*)data; #ifdef PCSX2_DEBUG - u32 memsize = VIFdmanum ? 0x4000 : 0x1000; + u32 memsize = vif_size(VIFdmanum); #endif if (VIFdmanum == 0) @@ -381,7 +311,7 @@ static int VIFalign(u32 *data, vifCode *v, unsigned int size, const unsigned int { int unpacksize; - //This is just to make sure the alignment isnt loopy on a split packet + //This is just to make sure the alignment isn't loopy on a split packet if(vifRegs->offset != ((vif->tag.addr & 0xf) >> 2)) { DevCon.Error("Warning: Unpack alignment error"); @@ -426,16 +356,16 @@ static int VIFalign(u32 *data, vifCode *v, unsigned int size, const unsigned int dest += (4 - ft->qsize) + unpacksize; } - if (vif->tag.addr >= (u32)(VIFdmanum ? 0x4000 : 0x1000)) + if (vif->tag.addr >= (u32)vif_size(VIFdmanum)) { - vif->tag.addr &= (u32)(VIFdmanum ? 0x3fff : 0xfff); + vif->tag.addr &= (u32)(vif_size(VIFdmanum) - 1); dest = (u32*)(VU->Mem + v->addr); } cdata += unpacksize * ft->dsize; vif->cl = 0; VIFUNPACK_LOG("Aligning packet done size = %d offset %d addr %x", size, vifRegs->offset, vif->tag.addr); - if((size & 0xf) == 0)return size >> 2; + if ((size & 0xf) == 0) return size >> 2; } else @@ -443,9 +373,9 @@ static int VIFalign(u32 *data, vifCode *v, unsigned int size, const unsigned int vif->tag.addr += ((4 - ft->qsize) + unpacksize) * 4; dest += (4 - ft->qsize) + unpacksize; - if (vif->tag.addr >= (u32)(VIFdmanum ? 0x4000 : 0x1000)) + if (vif->tag.addr >= (u32)vif_size(VIFdmanum)) { - vif->tag.addr &= (u32)(VIFdmanum ? 0x3fff : 0xfff); + vif->tag.addr &= (u32)(vif_size(VIFdmanum) - 1); dest = (u32*)(VU->Mem + v->addr); } @@ -460,9 +390,9 @@ static int VIFalign(u32 *data, vifCode *v, unsigned int size, const unsigned int if (vifRegs->cycle.cl >= vifRegs->cycle.wl) // skipping write { - if (vif->tag.addr >= (u32)(VIFdmanum ? 0x4000 : 0x1000)) + if (vif->tag.addr >= (u32)vif_size(VIFdmanum)) { - vif->tag.addr &= (u32)(VIFdmanum ? 0x3fff : 0xfff); + vif->tag.addr &= (u32)(vif_size(VIFdmanum) - 1); dest = (u32*)(VU->Mem + v->addr); } // continuation from last stream @@ -483,7 +413,7 @@ static int VIFalign(u32 *data, vifCode *v, unsigned int size, const unsigned int vif->tag.addr += incdest * 4; vif->cl = 0; - if((size & 0xf) == 0)break; + if ((size & 0xf) == 0) break; } else { @@ -491,10 +421,9 @@ static int VIFalign(u32 *data, vifCode *v, unsigned int size, const unsigned int vif->tag.addr += 16; } - // Hurrah for the 4th occurrance of this piece of code in this function... - if (vif->tag.addr >= (u32)(VIFdmanum ? 0x4000 : 0x1000)) + if (vif->tag.addr >= (u32)vif_size(VIFdmanum)) { - vif->tag.addr &= (u32)(VIFdmanum ? 0x3fff : 0xfff); + vif->tag.addr &= (u32)(vif_size(VIFdmanum) - 1); dest = (u32*)(VU->Mem + v->addr); } } @@ -514,10 +443,10 @@ static int VIFalign(u32 *data, vifCode *v, unsigned int size, const unsigned int { //VIF_LOG("warning, end with size = %d", size); /* unpack one qword */ - if(vif->tag.addr + ((size / ft->dsize) * 4) >= (u32)(VIFdmanum ? 0x4000 : 0x1000)) + if(vif->tag.addr + ((size / ft->dsize) * 4) >= (u32)vif_size(VIFdmanum)) { //DevCon.Notice("Overflow"); - vif->tag.addr &= (u32)(VIFdmanum ? 0x3fff : 0xfff); + vif->tag.addr &= (u32)(vif_size(VIFdmanum) - 1); dest = (u32*)(VU->Mem + v->addr); } @@ -540,7 +469,9 @@ static int VIFalign(u32 *data, vifCode *v, unsigned int size, const unsigned int return size>>2; } -static void VIFunpack(u32 *data, vifCode *v, unsigned int size, const unsigned int VIFdmanum) +template void VIFunpack<0>(u32 *data, vifCode *v, u32 size); +template void VIFunpack<1>(u32 *data, vifCode *v, u32 size); +template void VIFunpack(u32 *data, vifCode *v, u32 size) { u32 *dest; u32 unpackType; @@ -549,7 +480,7 @@ static void VIFunpack(u32 *data, vifCode *v, unsigned int size, const unsigned i VURegs * VU; u8 *cdata = (u8*)data; u32 tempsize = 0; - const u32 memlimit = (VIFdmanum ? 0x4000 : 0x1000); + const u32 memlimit = vif_size(VIFdmanum); #ifdef PCSX2_DEBUG u32 memsize = memlimit; @@ -754,7 +685,7 @@ static void VIFunpack(u32 *data, vifCode *v, unsigned int size, const unsigned i { if(v->addr >= memlimit) { - DevCon.Notice("Mem limit ovf"); + DevCon.Notice("Mem limit overflow"); v->addr &= (memlimit - 1); dest = (u32*)(VU->Mem + v->addr); } @@ -866,7 +797,9 @@ static void VIFunpack(u32 *data, vifCode *v, unsigned int size, const unsigned i } } -static void vuExecMicro(u32 addr, const u32 VIFdmanum) +template void vuExecMicro<0>(u32 addr); +template void vuExecMicro<1>(u32 addr); +template void vuExecMicro(u32 addr) { VURegs * VU; @@ -911,1916 +844,3 @@ static void vuExecMicro(u32 addr, const u32 VIFdmanum) else vu1ExecMicro(addr); } - -void vif0Init() -{ - for (u32 i = 0; i < 256; ++i) - { - s_maskwrite[i] = ((i & 3) == 3) || ((i & 0xc) == 0xc) || ((i & 0x30) == 0x30) || ((i & 0xc0) == 0xc0); - } - - SetNewMask(g_vif0Masks, g_vif0HasMask3, 0, 0xffffffff); -} - -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 Shouldnt go here CMD = %x", vif0Regs->code); - vif0.cmd = 0; - return 0; -} - -static int __fastcall Vif0TransSTMask(u32 *data) // STMASK -{ - SetNewMask(g_vif0Masks, g_vif0HasMask3, data[0], vif0Regs->mask); - 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; - assert(vif0.tag.addr < 4); - ret = min(4 - vif0.tag.addr, vif0.vifpacketsize); - assert(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.Notice("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.Notice("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 -{ - int ret; - - FreezeXMMRegs(1); - if (vif0.vifpacketsize < vif0.tag.size) - { - if(vif0Regs->offset != 0 || vif0.cl != 0) - { - ret = vif0.tag.size; - vif0.tag.size -= vif0.vifpacketsize - VIFalign(data, &vif0.tag, vif0.vifpacketsize, VIF0dmanum); - ret = ret - vif0.tag.size; - data += ret; - - if(vif0.vifpacketsize > 0) VIFunpack(data, &vif0.tag, vif0.vifpacketsize - ret, VIF0dmanum); - - ProcessMemSkip((vif0.vifpacketsize - ret) << 2, (vif0.cmd & 0xf), VIF0dmanum); - vif0.tag.size -= (vif0.vifpacketsize - ret); - FreezeXMMRegs(0); - - return vif0.vifpacketsize; - } - /* size is less that the total size, transfer is 'in pieces' */ - VIFunpack(data, &vif0.tag, vif0.vifpacketsize, VIF0dmanum); - - ProcessMemSkip(vif0.vifpacketsize << 2, (vif0.cmd & 0xf), VIF0dmanum); - - ret = vif0.vifpacketsize; - vif0.tag.size -= ret; - } - else - { - /* we got all the data, transfer it fully */ - ret = vif0.tag.size; - - //Align data after a split transfer first - if ((vif0Regs->offset != 0) || (vif0.cl != 0)) - { - vif0.tag.size = VIFalign(data, &vif0.tag, vif0.tag.size, VIF0dmanum); - data += ret - vif0.tag.size; - if(vif0.tag.size > 0) VIFunpack(data, &vif0.tag, vif0.tag.size, VIF0dmanum); - } - else - { - VIFunpack(data, &vif0.tag, vif0.tag.size, VIF0dmanum); - } - - vif0.tag.size = 0; - vif0.cmd = 0; - } - - FreezeXMMRegs(0); - return ret; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// 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 = 1; - vif0.cmd &= ~0x7f; -} - -static void Vif0CMDFlushE() // FLUSHE -{ - vif0FLUSH(); - vif0.cmd &= ~0x7f; -} - -static void Vif0CMDMSCALF() //MSCAL/F -{ - vuExecMicro((u16)(vif0Regs->code) << 3, VIF0dmanum); - vif0.cmd &= ~0x7f; -} - -static void Vif0CMDMSCNT() // MSCNT -{ - vuExecMicro(-1, VIF0dmanum); - 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 = 1; - vif0.irq++; - } - vif0.cmd &= ~0x7f; -} - -int VIF0transfer(u32 *data, int size, int 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 = 1; - 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 = 1; - //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 -2; - } - - vif0Regs->stat.VPS = 0; //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 0; -} - -int _VIF0chain() -{ - u32 *pMem; - u32 ret; - - if ((vif0ch->qwc == 0) && !vif0.vifstalled) return 0; - - pMem = (u32*)dmaGetAddr(vif0ch->madr); - if (pMem == NULL) - { - vif0.cmd = 0; - vif0.tag.size = 0; - vif0ch->qwc = 0; - return 0; - } - - if (vif0.vifstalled) - ret = VIF0transfer(pMem + vif0.irqoffset, vif0ch->qwc * 4 - vif0.irqoffset, 0); - else - ret = VIF0transfer(pMem, vif0ch->qwc * 4, 0); - - return ret; -} - -int _chainVIF0() -{ - int id, ret; - - vif0ptag = (u32*)dmaGetAddr(vif0ch->tadr); //Set memory pointer to TADR - - if (!(Tag::Transfer("Vif0 Tag", vif0ch, vif0ptag))) return -1; - - vif0ch->madr = vif0ptag[1]; // MADR = ADDR field - id = Tag::Id(vif0ptag); // ID for DmaChain copied from bit 28 of the tag - 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", - vif0ptag[1], vif0ptag[0], vif0ch->qwc, id, vif0ch->madr, vif0ch->tadr); - - // Transfer dma tag if tte is set - if (vif0ch->chcr.TTE) - { - if (vif0.vifstalled) - ret = VIF0transfer(vif0ptag + (2 + vif0.irqoffset), 2 - vif0.irqoffset, 1); //Transfer Tag on stall - else - ret = VIF0transfer(vif0ptag + 2, 2, 1); //Transfer Tag - - if (ret == -1) return -1; //There has been an error - if (ret == -2) return -2; //IRQ set by VIFTransfer - } - - vif0.done |= hwDmacSrcChainWithStack(vif0ch, id); - - VIF_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx", - vif0ptag[1], vif0ptag[0], vif0ch->qwc, id, vif0ch->madr, vif0ch->tadr); - - ret = _VIF0chain(); //Transfers the data set by the switch - - if (vif0ch->chcr.TIE && Tag::IRQ(vif0ptag)) //Check TIE bit of CHCR and IRQ bit of tag - { - VIF_LOG("dmaIrq Set\n"); - - vif0.done = true; //End Transfer - } - return (vif0.done) ? 1: 0; //Return 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 = 1; - hwIntcIrq(VIF0intc); - --vif0.irq; - - if (vif0Regs->stat.test(VIF0_STAT_VSS | VIF0_STAT_VIS | VIF0_STAT_VFS)) - { - vif0Regs->stat.FQC = 0; // FQC=0 - vif0ch->chcr.STR = 0; - return; - } - - if (vif0ch->qwc > 0 || vif0.irqoffset > 0) - { - if (vif0.stallontag) - _chainVIF0(); - else - _VIF0chain(); - - CPU_INT(0, g_vifCycles); - 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); - 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 = 0; - hwDmacIrq(DMAC_VIF0); - vif0Regs->stat.FQC = 0; // 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() == -2) - { - Console.WriteLn("Stall on normal %x", vif0Regs->stat._u32); - - vif0.vifstalled = true; - return; - } - - vif0.done = true; - CPU_INT(0, g_vifCycles); - 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 = 0; - 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._u32 = 0; - vif0Regs->stat.clear(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 = 1; - vif0Regs->stat.VPS = 0; - 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 = 1; - vif0Regs->stat.VPS = 0; - 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(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 = 1; - 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._u32 = value; - break; - - case VIF0_R0: - case VIF0_R1: - case VIF0_R2: - case VIF0_R3: - assert((mem&0xf) == 0); - g_vifmask.Row0[(mem>>4) & 3] = value; - break; - - case VIF0_C0: - case VIF0_C1: - case VIF0_C2: - case VIF0_C3: - assert((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); - SetNewMask(g_vif0Masks, g_vif0HasMask3, 0, 0xffffffff); - - psHu64(VIF0_FIFO) = 0; - psHu64(VIF0_FIFO + 8) = 0; - - vif0Regs->stat.VPS = 0; - vif0Regs->stat.FQC = 0; - - vif0.done = true; -} - -void SaveStateBase::vif0Freeze() -{ - 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); - Freeze(g_vif0Masks); -} - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - - -void vif1Init() -{ - SetNewMask(g_vif1Masks, g_vif1HasMask3, 0, 0xffffffff); -} - -static __forceinline void vif1UNPACK(u32 *data) -{ - int vifNum; - - if (vif1Regs->cycle.wl == 0) - { - if (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); - }*/ - assert(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("Shouldnt go here CMD = %x", vif1Regs->code); - vif1.cmd = 0; - return 0; -} -static int __fastcall Vif1TransSTMask(u32 *data) // STMASK -{ - SetNewMask(g_vif1Masks, g_vif1HasMask3, data[0], vif1Regs->mask); - 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) -{ - int ret; - - u32* pmem = &vif1Regs->r0 + (vif1.tag.addr << 2); - u32* pmem2 = g_vifmask.Row1 + vif1.tag.addr; - assert(vif1.tag.addr < 4); - ret = min(4 - vif1.tag.addr, vif1.vifpacketsize); - assert(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.Notice("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.Notice("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 = 1; - return 0; - } - } - - gifRegs->stat.APATH |= GIF_APATH2; - gifRegs->stat.OPH = 1; - - - 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--; - } - } - - FreezeRegs(1); - // copy 16 bytes the fast way: - const u64* src = (u64*)splittransfer[0]; - mtgsThread.PrepDataPacket(GIF_PATH_2, nloop0_packet, 1); - u64* dst = (u64*)mtgsThread.GetDataPacketPtr(); - dst[0] = src[0]; - dst[1] = src[1]; - - mtgsThread.SendDataPacket(); - FreezeRegs(0); - - 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(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 ? - - FreezeRegs(1); - - // Round ret up, just in case it's not 128bit aligned. - const uint count = mtgsThread.PrepDataPacket(GIF_PATH_2, data, (ret + 3) >> 2); - memcpy_fast(mtgsThread.GetDataPacketPtr(), data, count << 4); - mtgsThread.SendDataPacket(); - - FreezeRegs(0); - - return ret; -} - -static int __fastcall Vif1TransUnpack(u32 *data) -{ - FreezeXMMRegs(1); - - if (vif1.vifpacketsize < vif1.tag.size) - { - int ret = vif1.tag.size; - /* size is less that the total size, transfer is 'in pieces' */ - if (vif1Regs->offset != 0 || vif1.cl != 0) - { - vif1.tag.size -= vif1.vifpacketsize - VIFalign(data, &vif1.tag, vif1.vifpacketsize, VIF1dmanum); - ret = ret - vif1.tag.size; - data += ret; - if((vif1.vifpacketsize - ret) > 0) VIFunpack(data, &vif1.tag, vif1.vifpacketsize - ret, VIF1dmanum); - ProcessMemSkip((vif1.vifpacketsize - ret) << 2, (vif1.cmd & 0xf), VIF1dmanum); - vif1.tag.size -= (vif1.vifpacketsize - ret); - } - else - { - VIFunpack(data, &vif1.tag, vif1.vifpacketsize, VIF1dmanum); - - ProcessMemSkip(vif1.vifpacketsize << 2, (vif1.cmd & 0xf), VIF1dmanum); - vif1.tag.size -= vif1.vifpacketsize; - } - - FreezeXMMRegs(0); - return vif1.vifpacketsize; - } - else - { - int ret = vif1.tag.size; - - if (vif1Regs->offset != 0 || vif1.cl != 0) - { - vif1.tag.size = VIFalign(data, &vif1.tag, vif1.tag.size, VIF1dmanum); - data += ret - vif1.tag.size; - if (vif1.tag.size > 0) VIFunpack(data, &vif1.tag, vif1.tag.size, VIF1dmanum); - } - else - { - /* we got all the data, transfer it fully */ - VIFunpack(data, &vif1.tag, vif1.tag.size, VIF1dmanum); - } - - vif1.tag.size = 0; - vif1.cmd = 0; - FreezeXMMRegs(0); - return ret; - } - -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// 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 = 0; - 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 = 1; - } - else - { - //Let the Gif know it can transfer again (making sure any vif stall isnt unset prematurely) - Path3progress = TRANSFER_MODE; - gifRegs->stat.IMT = 0; - 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 = 1; - 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 = 1; - CPU_INT(2, 4); - } - } - - vif1.cmd &= ~0x7f; -} - -static void Vif1CMDMSCALF() //MSCAL/F -{ - vif1FLUSH(); - vuExecMicro((u16)(vif1Regs->code) << 3, VIF1dmanum); - vif1.cmd &= ~0x7f; -} - -static void Vif1CMDMSCNT() // MSCNT -{ - vuExecMicro(-1, VIF1dmanum); - 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 = 1; - 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 -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -int VIF1transfer(u32 *data, int size, int 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 = 1; - 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 = 1; // 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 -2; - - 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 -2; - } - - vif1Regs->stat.VPS = 0; //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 ? -2 : 0; -} - -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 = 1; //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. - - FreezeXMMRegs(1); - - if (GSreadFIFO2 == NULL) - { - for (size = vif1ch->qwc; size > 0; --size) - { - if (size > 1) - { - mtgsWaitGS(); - GSreadFIFO((u64*)&PS2MEM_HW[0x5000]); - } - pMem[0] = psHu64(VIF1_FIFO); - pMem[1] = psHu64(VIF1_FIFO + 8); - pMem += 2; - } - } - else - { - mtgsWaitGS(); - GSreadFIFO2(pMem, vif1ch->qwc); - - // set incase read - psHu64(VIF1_FIFO) = pMem[2*vif1ch->qwc-2]; - psHu64(VIF1_FIFO + 8) = pMem[2*vif1ch->qwc-1]; - } - - FreezeXMMRegs(0); - - g_vifCycles += vif1ch->qwc * 2; - vif1ch->madr += vif1ch->qwc * 16; // mgs3 scene changes - vif1ch->qwc = 0; -} - -int _VIF1chain() -{ - u32 *pMem; - u32 ret; - - if (vif1ch->qwc == 0) - { - vif1.inprogress = 0; - return 0; - } - - if (vif1.dmamode == VIF_NORMAL_FROM_MEM_MODE) - { - vif1TransferFromMemory(); - vif1.inprogress = 0; - return 0; - } - - pMem = (u32*)dmaGetAddr(vif1ch->madr); - if (pMem == NULL) - { - vif1.cmd = 0; - vif1.tag.size = 0; - vif1ch->qwc = 0; - return 0; - } - - VIF_LOG("VIF1chain size=%d, madr=%lx, tadr=%lx", - vif1ch->qwc, vif1ch->madr, vif1ch->tadr); - - if (vif1.vifstalled) - ret = VIF1transfer(pMem + vif1.irqoffset, vif1ch->qwc * 4 - vif1.irqoffset, 0); - else - ret = VIF1transfer(pMem, vif1ch->qwc * 4, 0); - - return ret; -} - -bool _chainVIF1() -{ - return vif1.done; // Return Done -} - -__forceinline void vif1SetupTransfer() -{ - 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: - int id; - int ret; - - vif1ptag = (u32*)dmaGetAddr(vif1ch->tadr); //Set memory pointer to TADR - - if (!(Tag::Transfer("Vif1 Tag", vif1ch, vif1ptag))) return; - - vif1ch->madr = vif1ptag[1]; //MADR = ADDR field - g_vifCycles += 1; // Add 1 g_vifCycles from the QW read for the tag - id = Tag::Id(vif1ptag); //ID for DmaChain copied from bit 28 of 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", - vif1ptag[1], vif1ptag[0], vif1ch->qwc, id, vif1ch->madr, vif1ch->tadr); - - if (!vif1.done && ((dmacRegs->ctrl.STD == STD_VIF1) && (id == 4))) // 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) - { - - if (vif1.vifstalled) - ret = VIF1transfer(vif1ptag + (2 + vif1.irqoffset), 2 - vif1.irqoffset, 1); //Transfer Tag on stall - else - ret = VIF1transfer(vif1ptag + 2, 2, 1); //Transfer Tag - - if (ret < 0 && 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, id); - - //Check TIE bit of CHCR and IRQ bit of tag - if (vif1ch->chcr.TIE && (Tag::IRQ(vif1ptag))) - { - 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 = 0; - } - } - - if (!(vif1ch->chcr.STR)) Console.WriteLn("Vif1 running when CHCR == %x", vif1ch->chcr._u32); - - if (vif1.irq && vif1.tag.size == 0) - { - vif1Regs->stat.INT = 1; - 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 = 0; - 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); - 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); - 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 = 0; //Vif goes idle as the stall happened between commands; - vif1ch->chcr.STR = 0; - 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, 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); - 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.set(min((u16)16, vif1ch->qwc) << 24); - - // 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 = 0; - vif1Regs->mark = value; - break; - - case VIF1_FBRST: // FBRST - VIF_LOG("VIF1_FBRST write32 0x%8.8x", value); - - if (value & 0x1) // 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 = 0; - if (gif->chcr.STR) CPU_INT(2, 4); - } - - vif1Regs->err._u32 = 0; - vif1.inprogress = 0; - vif1Regs->stat.clear(VIF1_STAT_FQC | VIF1_STAT_FDR | VIF1_STAT_INT | VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS | VIF1_STAT_VPS); // FQC=0 - } - - if (value & 0x2) // Forcebreak Vif. - { - /* I guess we should stop the VIF dma here, but not 100% sure (linuz) */ - vif1Regs->stat.VFS = 1; - vif1Regs->stat.VPS = 0; - cpuRegs.interrupt &= ~((1 << 1) | (1 << 10)); //Stop all vif1 DMA's - vif1.vifstalled = true; - Console.WriteLn("vif1 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). - vif1Regs->stat.VSS = 1; - vif1Regs->stat.VPS = 0; - cpuRegs.interrupt &= ~((1 << 1) | (1 << 10)); //Stop all vif1 DMA's - vif1.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 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(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 = 1; - } - } - } - break; - - case VIF1_ERR: // ERR - VIF_LOG("VIF1_ERR write32 0x%8.8x", value); - - /* Set VIF1_ERR with 'value' */ - vif1Regs->err._u32 = 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) ^(value & VIF1_STAT_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._u32 = (vif1Regs->stat.test(~VIF1_STAT_FDR)) | (value & VIF1_STAT_FDR); - if (vif1Regs->stat.FDR) - { - vif1Regs->stat.FQC = 1; // FQC=1 - hack but it checks this is true before transfer? (fatal frame) - } - else - { - vif1ch->qwc = 0; - vif1.vifstalled = false; - vif1.done = true; - vif1Regs->stat.FQC = 0; // FQC=0 - } - break; - - case VIF1_MODE: // MODE - vif1Regs->mode = value; - break; - - case VIF1_R0: - case VIF1_R1: - case VIF1_R2: - case VIF1_R3: - assert((mem&0xf) == 0); - g_vifmask.Row1[(mem>>4) & 3] = value; - break; - - case VIF1_C0: - case VIF1_C1: - case VIF1_C2: - case VIF1_C3: - assert((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); - SetNewMask(g_vif1Masks, g_vif1HasMask3, 0, 0xffffffff); - - psHu64(VIF1_FIFO) = 0; - psHu64(VIF1_FIFO + 8) = 0; - - vif1Regs->stat.VPS = 0; - vif1Regs->stat.FQC = 0; // FQC=0 - - vif1.done = true; - cpuRegs.interrupt &= ~((1 << 1) | (1 << 10)); //Stop all vif1 DMA's -} - -void SaveStateBase::vif1Freeze() -{ - Freeze(vif1); - - Freeze(g_vif1HasMask3); - Freeze(g_vif1Masks); -} diff --git a/pcsx2/VifDma.h b/pcsx2/VifDma.h index d79e12566e..8cfe194505 100644 --- a/pcsx2/VifDma.h +++ b/pcsx2/VifDma.h @@ -90,8 +90,8 @@ void __fastcall UNPACK_V4_5( u32 *dest, u32 *data, int size ); void vifDmaInit(); void vif0Init(); void vif1Init(); -extern void vif0Interrupt(); -extern void vif1Interrupt(); +extern void vif0Interrupt(); +extern void vif1Interrupt(); extern void Vif1MskPath3(); void vif0Write32(u32 mem, u32 value); @@ -100,4 +100,9 @@ void vif1Write32(u32 mem, u32 value); void vif0Reset(); void vif1Reset(); +__forceinline static int _limit(int a, int max) +{ + return ((a > max) ? max : a); +} + #endif diff --git a/pcsx2/VifDma_internal.h b/pcsx2/VifDma_internal.h new file mode 100644 index 0000000000..11366a14b4 --- /dev/null +++ b/pcsx2/VifDma_internal.h @@ -0,0 +1,61 @@ +/* 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 . + */ + +#ifndef __VIFDMA_INTERNAL_H__ +#define __VIFDMA_INTERNAL_H__ + +// Generic constants +static const unsigned int VIF0intc = 4; +static const unsigned int VIF1intc = 5; + +typedef void (__fastcall *UNPACKFUNCTYPE)(u32 *dest, u32 *data, int size); +typedef int (*UNPACKPARTFUNCTYPESSE)(u32 *dest, u32 *data, int size); + +struct VIFUnpackFuncTable +{ + UNPACKFUNCTYPE funcU; + UNPACKFUNCTYPE funcS; + + u32 bsize; // currently unused + u32 dsize; // byte size of one channel + u32 gsize; // size of data in bytes used for each write cycle + u32 qsize; // used for unpack parts, num of vectors that + // will be decompressed from data for 1 cycle +}; + +extern int g_vifCycles; +extern u8 s_maskwrite[256]; +extern const VIFUnpackFuncTable VIFfuncTable[16]; +extern __aligned16 u32 g_vif0Masks[64], g_vif1Masks[64]; +extern u32 g_vif0HasMask3[4], g_vif1HasMask3[4]; + +template void ProcessMemSkip(u32 size, u32 unpackType); +template u32 VIFalign(u32 *data, vifCode *v, u32 size); +template void VIFunpack(u32 *data, vifCode *v, u32 size); +template void vuExecMicro(u32 addr); +extern __forceinline void vif0FLUSH(); +extern __forceinline void vif1FLUSH(); + +__forceinline static u32 vif_size(u8 num) +{ + if (num == 0) + return 0x1000; + else if (num == 1) + return 0x4000; + + return 0; +} + +#endif diff --git a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj index 13561b2b08..b1259fa82f 100644 --- a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj +++ b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj @@ -820,10 +820,22 @@ RelativePath="..\..\VifDma.cpp" > + + + + + +