Files
archived-pcsx2/pcsx2/Vif_Transfer.cpp
refraction d29a30c265 VIF: Reworked the VU delays in to scheduled events to simulate VU run time without killing Metal Saga or Fahrenheit. Adjusted the COP checks on the VU's to use the same method as the VPU_STAT is never set essentially so the VU is never "running".
Path3 Masking: Fixed a bug which caused persona 3 not to boot, previous a hack had been put in place to get around this.
VIF: Fixed a VIF error with the rare game Realta Nua, now goes through the prologue correctly. Game requires the EE timing hack to get rid of most of the noise (Path3 masking problem with new GIF unit, unfixable).

Expecting bugs, I will be monitoring this.


git-svn-id: http://pcsx2.googlecode.com/svn/trunk@5147 96395faa-99c1-11dd-bbfe-3dabce05a288
2012-04-07 01:48:34 +00:00

176 lines
5.4 KiB
C++

/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 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 <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "Common.h"
#include "Vif_Dma.h"
#include "newVif.h"
//------------------------------------------------------------------
// VifCode Transfer Interpreter (Vif0/Vif1)
//------------------------------------------------------------------
// Doesn't stall if the next vifCode is the Mark command
_vifT bool runMark(u32* &data) {
if (((vifXRegs.code >> 24) & 0x7f) == 0x7) {
//DevCon.WriteLn("Vif%d: Running Mark with I-bit", idx);
return 1; // No Stall?
}
return 1; // Stall
}
// Returns 1 if i-bit && finished vifcode && i-bit not masked
_vifT bool analyzeIbit(u32* &data, int iBit) {
vifStruct& vifX = GetVifX;
if (iBit && !vifX.cmd && !vifXRegs.err.MII) {
//DevCon.WriteLn("Vif I-Bit IRQ");
vifX.irq++;
// Okay did some testing with Max Payne, it does this:
// VifMark value = 0x666 (i know, evil!)
// NOP with I Bit
// VifMark value = 0
//
// If you break after the 2nd Mark has run, the game reports invalid mark 0 and the game dies.
// So it has to occur here, testing a theory that it only doesn't stall if the command with
// the iBit IS mark, but still sends the IRQ to let the cpu know the mark is there. (Refraction)
//
// --------------------------
//
// This is how it probably works: i-bit sets the IRQ flag, and VIF keeps running until it encounters
// a non-MARK instruction. This includes the *current* instruction. ie, execution only continues
// unimpeded if MARK[i] is specified, and keeps executing unimpeded until any non-MARK command.
// Any other command with an I bit should stall immediately.
// Example:
//
// VifMark[i] value = 0x321 (with I bit)
// VifMark value = 0
// VifMark value = 0x333
// NOP
//
// ... the VIF should not stall and raise the interrupt until after the NOP is processed.
// So the final value for MARK as the game sees it will be 0x333. --air
if(CHECK_VIF1STALLHACK) return 0;
else return 1;
}
return 0;
}
// Interprets packet
_vifT void vifTransferLoop(u32* &data) {
vifStruct& vifX = GetVifX;
u32& pSize = vifX.vifpacketsize;
int iBit = vifX.cmd >> 7;
vifXRegs.stat.VPS |= VPS_TRANSFERRING;
vifXRegs.stat.ER1 = false;
while (pSize > 0 && !vifX.vifstalled) {
if(!vifX.cmd) { // Get new VifCode
vifXRegs.code = data[0];
vifX.cmd = data[0] >> 24;
iBit = data[0] >> 31;
//VIF_LOG("New VifCMD %x tagsize %x", vifX.cmd, vifX.tag.size);
if (IsDevBuild && SysTrace.EE.VIFcode.IsActive()) {
// Pass 2 means "log it"
vifCmdHandler[idx][vifX.cmd & 0x7f](2, data);
}
vifCmdHandler[idx][vifX.cmd & 0x7f](0, data);
data++; pSize--;
if (analyzeIbit<idx>(data, iBit)) break;
continue;
}
int ret = vifCmdHandler[idx][vifX.cmd & 0x7f](1, data);
data += ret;
pSize -= ret;
if (analyzeIbit<idx>(data, iBit)) break;
}
if (pSize) vifX.vifstalled = true;
}
_vifT static __fi bool vifTransfer(u32 *data, int size, bool TTE) {
vifStruct& vifX = GetVifX;
// irqoffset necessary to add up the right qws, or else will spin (spiderman)
int transferred = vifX.irqoffset;
vifX.irqoffset = 0;
vifX.vifstalled = false;
vifX.stallontag = false;
vifX.vifpacketsize = size;
vifTransferLoop<idx>(data);
transferred += size - vifX.vifpacketsize;
//Make this a minimum of 1 cycle so if it's the end of the packet it doesnt just fall through.
//Metal Saga can do this, just to be safe :)
if (!idx) g_vif0Cycles += max(1, (int)((transferred * BIAS) >> 2));
else g_vif1Cycles += max(1, (int)((transferred * BIAS) >> 2));
/*
if(!idx && g_vu0Cycles > 0) {
if (g_vif0Cycles < g_vu0Cycles) g_vu0Cycles -= g_vif0Cycles;
elif(g_vif0Cycles >= g_vu0Cycles) g_vu0Cycles = 0;
}
if (idx && g_vu1Cycles > 0) {
if (g_vif1Cycles < g_vu1Cycles) g_vu1Cycles -= g_vif1Cycles;
elif(g_vif1Cycles >= g_vu1Cycles) g_vu1Cycles = 0;
}
*/
vifX.irqoffset = transferred % 4; // cannot lose the offset
if (!TTE) {// *WARNING* - Tags CAN have interrupts! so lets just ignore the dma modifying stuffs (GT4)
transferred = transferred >> 2;
vifXch.madr +=(transferred << 4);
vifXch.qwc -= transferred;
if (vifXch.chcr.STR) hwDmacSrcTadrInc(vifXch);
if(!vifXch.qwc) {
vifX.inprogress &= ~0x1;
vifX.vifstalled = false;
}
}
else {
if (!vifX.irqoffset) vifX.vifstalled = false;
}
if (vifX.irq && vifX.cmd == 0) {
//DevCon.WriteLn("Vif IRQ!");
if(((vifXRegs.code >> 24) & 0x7f) != 0x7) {
vifXRegs.stat.VIS = true; // Note: commenting this out fixes WALL-E?
vifX.vifstalled = true;
}
}
return !vifX.vifstalled;
}
// When TTE is set to 1, MADR and QWC are not updated as part of the transfer.
bool VIF0transfer(u32 *data, int size, bool TTE) {
return vifTransfer<0>(data, size, TTE);
}
bool VIF1transfer(u32 *data, int size, bool TTE) {
return vifTransfer<1>(data, size, TTE);
}