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
This commit is contained in:
refraction 2012-04-07 01:48:34 +00:00
parent 2e22e56b48
commit d29a30c265
16 changed files with 162 additions and 106 deletions

View File

@ -22,17 +22,20 @@
using namespace R5900;
using namespace R5900::Interpreter;
//#define CP2COND (((VU0.VI[REG_VPU_STAT].US[0] >> 8) & 1))
#define CP2COND (vif1Regs.stat.VEW)
#define CP2COND (((VU0.VI[REG_VPU_STAT].US[0] >> 8) & 1))
//Run the FINISH either side of the VCALL's as we have no control over it past here.
void VCALLMS() {
vu0Finish();
vu0ExecMicro(((cpuRegs.code >> 6) & 0x7FFF) * 8);
vif0Regs.stat.VEW = false;
}
void VCALLMSR() {
vu0Finish();
vu0ExecMicro(VU0.VI[REG_CMSAR0].US[0] * 8);
vif0Regs.stat.VEW = false;
}
void BC2F()

View File

@ -583,7 +583,8 @@ struct Gif_Unit {
bool CanDoP3Slice() { return stat.IMT == 1 && gifPath[GIF_PATH_3].state == GIF_PATH_IMAGE; }
bool CanDoGif() { return stat.PSE == 0 && (CHECK_GIFREVERSEHACK ? 1 : stat.DIR == 0) && gsSIGNAL.queued == 0; }
bool Path3Masked() { return stat.M3R || stat.M3P; }
//Mask stops the next packet which hasnt started from transferring
bool Path3Masked() { return ((stat.M3R || stat.M3P) && (gifPath[GIF_PATH_3].state == GIF_PATH_IDLE)); }
void PrintInfo(bool printP1=1, bool printP2=1, bool printP3=1) {
u32 a = checkPaths(1,1,1), b = checkQueued(1,1,1);

View File

@ -292,7 +292,7 @@ static __fi void _cpuTestInterrupts()
// The following ints are rarely called. Encasing them in a conditional
// as follows helps speed up most games.
if( cpuRegs.interrupt & 0xF19 ) // Bits 0 3 4 8 9 10 11 ( 111100011001 )
if( cpuRegs.interrupt & 0x60F19 ) // Bits 0 3 4 8 9 10 11 17 18( 1100000111100011001 )
{
TESTINT(DMAC_VIF0, vif0Interrupt);
@ -304,6 +304,9 @@ static __fi void _cpuTestInterrupts()
TESTINT(DMAC_MFIFO_VIF, vifMFIFOInterrupt);
TESTINT(DMAC_MFIFO_GIF, gifMFIFOInterrupt);
TESTINT(VIF_VU0_FINISH, vif0VUFinish);
TESTINT(VIF_VU1_FINISH, vif1VUFinish);
}
}

View File

@ -405,8 +405,10 @@ enum EE_EventType
DMAC_STALL_SIS = 13, // SIS
DMAC_MFIFO_EMPTY = 14, // MEIS
DMAC_BUS_ERROR = 15, // BEIS
DMAC_GIF_UNIT
DMAC_GIF_UNIT,
VIF_VU0_FINISH,
VIF_VU1_FINISH
};
extern void CPU_INT( EE_EventType n, s32 ecycle );

View File

@ -46,6 +46,7 @@ void __fastcall vu0ExecMicro(u32 addr) {
VU0.VI[REG_VPU_STAT].UL &= ~0xFF;
VU0.VI[REG_VPU_STAT].UL |= 0x01;
vif0Regs.stat.VEW = true;
if ((s32)addr != -1) VU0.VI[REG_TPC].UL = addr;
_vuExecMicroDebug(VU0);

View File

@ -50,9 +50,10 @@ void vu1Finish() {
void __fastcall vu1ExecMicro(u32 addr)
{
vif1Regs.stat.VEW = true;
if (THREAD_VU1) {
vu1Thread.ExecuteVU(addr, vif1Regs.top, vif1Regs.itop);
vif1Regs.stat.VEW = false;
VU0.VI[REG_VPU_STAT].UL &= ~0xFF00;
return;
}
@ -64,7 +65,6 @@ void __fastcall vu1ExecMicro(u32 addr)
VU0.VI[REG_VPU_STAT].UL &= ~0xFF00;
VU0.VI[REG_VPU_STAT].UL |= 0x0100;
vif1Regs.stat.VEW = true;
if ((s32)addr != -1) VU1.VI[REG_TPC].UL = addr;
_vuExecMicroDebug(VU1);

View File

@ -47,8 +47,6 @@ void SaveStateBase::vif0Freeze()
FreezeTag("VIF0dma");
Freeze(g_vif0Cycles);
Freeze(g_vu0Cycles);
Freeze(g_packetsizeonvu0);
Freeze(vif0);
@ -61,8 +59,6 @@ void SaveStateBase::vif1Freeze()
FreezeTag("VIF1dma");
Freeze(g_vif1Cycles);
Freeze(g_vu1Cycles);
Freeze(g_packetsizeonvu1);
Freeze(vif1);

View File

@ -25,31 +25,11 @@ u32 g_vif0Cycles = 0;
// because its vif stalling not the EE core...
__fi void vif0FLUSH()
{
if(g_packetsizeonvu0 > vif0.vifpacketsize && g_vu0Cycles > 0)
{
//DevCon.Warning("Adding on same packet");
if( ((g_packetsizeonvu0 - vif0.vifpacketsize) >> 1) > g_vu0Cycles)
g_vu0Cycles -= (g_packetsizeonvu0 - vif0.vifpacketsize) >> 1;
else g_vu0Cycles = 0;
}
if(g_vu0Cycles > 0)
{
//DevCon.Warning("Adding %x cycles to VIF0", g_vu0Cycles * BIAS);
g_vif0Cycles += g_vu0Cycles;
g_vu0Cycles = 0;
}
g_vu0Cycles = 0;
if (!(VU0.VI[REG_VPU_STAT].UL & 1)) return;
if(VU0.flags & VUFLAG_MFLAGSET)
if(vif0Regs.stat.VEW == true)
{
vif0.waitforvu = true;
vif0.vifstalled = true;
return;
}
int _cycles = VU0.cycle;
vu0Finish();
//DevCon.Warning("VIF0 adding %x cycles", (VU0.cycle - _cycles) * BIAS);
g_vif0Cycles += (VU0.cycle - _cycles) * BIAS;
return;
}
@ -160,6 +140,27 @@ __fi void vif0SetupTransfer()
}
}
__fi void vif0VUFinish()
{
if ((VU0.VI[REG_VPU_STAT].UL & 1))
{
int _cycles = VU0.cycle;
//DevCon.Warning("Finishing VU0");
vu0Finish();
_cycles = VU0.cycle - _cycles;
//DevCon.Warning("Finishing VU0 %d cycles", _cycles);
CPU_INT(VIF_VU0_FINISH, _cycles * BIAS);
return;
}
vif0Regs.stat.VEW = false;
if(vif0.waitforvu == true)
{
vif0.waitforvu = false;
ExecuteVU(0);
}
//DevCon.Warning("VU0 state cleared");
}
__fi void vif0Interrupt()
{
VIF_LOG("vif0Interrupt: %8.8x", cpuRegs.cycle);
@ -190,6 +191,12 @@ __fi void vif0Interrupt()
}
}
if(vif0.waitforvu == true)
{
//DevCon.Warning("Waiting on VU0");
CPU_INT(DMAC_VIF0, 16);
return;
}
//Must go after the Stall, incase it's still in progress, GTC africa likes to see it still transferring.
if (vif0.cmd)
{
@ -250,7 +257,6 @@ void dmaVIF0()
vif0ch.tadr, vif0ch.asr0, vif0ch.asr1);
g_vif0Cycles = 0;
g_vu0Cycles = 0;
//if(vif0.irqoffset != 0 && vif0.vifstalled == true) DevCon.Warning("Offset on VIF0 start! offset %x, Progress %x", vif0.irqoffset, vif0.vifstalled);
/*vif0.irqoffset = 0;
vif0.vifstalled = false;

View File

@ -25,27 +25,10 @@ u32 g_vif1Cycles = 0;
__fi void vif1FLUSH()
{
if(g_packetsizeonvu1 > vif1.vifpacketsize && g_vu1Cycles > 0)
if(vif1Regs.stat.VEW == true)
{
//DevCon.Warning("Adding on same packet");
if( ((g_packetsizeonvu1 - vif1.vifpacketsize) >> 1) > g_vu1Cycles)
g_vu1Cycles -= (g_packetsizeonvu1 - vif1.vifpacketsize) >> 1;
else g_vu1Cycles = 0;
}
if(g_vu1Cycles > 0)
{
//DevCon.Warning("Adding %x cycles to VIF1", g_vu1Cycles * BIAS);
g_vif1Cycles += g_vu1Cycles;
g_vu1Cycles = 0;
}
g_vu1Cycles = 0;//else DevCon.Warning("VIF1 Different Packet, how can i work this out :/");
if (VU0.VI[REG_VPU_STAT].UL & 0x100)
{
int _cycles = VU1.cycle;
vu1Finish();
//DevCon.Warning("VIF1 adding %x cycles", (VU1.cycle - _cycles) * BIAS);
g_vif1Cycles += (VU1.cycle - _cycles) * BIAS;
vif1.waitforvu = true;
vif1.vifstalled = true;
}
}
@ -230,9 +213,30 @@ __fi void vif1SetupTransfer()
}
}
__fi void vif1VUFinish()
{
if (VU0.VI[REG_VPU_STAT].UL & 0x100)
{
int _cycles = VU1.cycle;
//DevCon.Warning("Finishing VU1");
vu1Finish();
CPU_INT(VIF_VU1_FINISH, (VU1.cycle - _cycles) * BIAS);
return;
}
vif1Regs.stat.VEW = false;
if(vif1.waitforvu == true)
{
vif1.waitforvu = false;
ExecuteVU(1);
}
//DevCon.Warning("VU1 state cleared");
}
__fi void vif1Interrupt()
{
VIF_LOG("vif1Interrupt: %8.8x", cpuRegs.cycle);
VIF_LOG("vif1Interrupt: %8.8x chcr %x, done %x, qwc %x", cpuRegs.cycle, vif1ch.chcr._u32, vif1.done, vif1ch.qwc);
g_vif1Cycles = 0;
@ -262,6 +266,12 @@ __fi void vif1Interrupt()
//Simulated GS transfer time done, clear the flags
}
if(vif1.waitforvu == true)
{
//DevCon.Warning("Waiting on VU1");
CPU_INT(DMAC_VIF1, 16);
return;
}
if (!vif1ch.chcr.STR) Console.WriteLn("Vif1 running when CHCR == %x", vif1ch.chcr._u32);
if (vif1.irq && vif1.tag.size == 0)
@ -294,19 +304,7 @@ __fi void vif1Interrupt()
{
vif1Regs.stat.VPS = VPS_IDLE;
}
if (vif1.inprogress & 0x1)
{
_VIF1chain();
// VIF_NORMAL_FROM_MEM_MODE is a very slow operation.
// Timesplitters 2 depends on this beeing a bit higher than 128.
if (vif1ch.chcr.DIR) vif1Regs.stat.FQC = min(vif1ch.qwc, (u16)16);
// Refraction - Removing voodoo timings for now, completely messes a lot of Path3 masked games.
/*if (vif1.dmamode == VIF_NORMAL_FROM_MEM_MODE ) CPU_INT(DMAC_VIF1, 1024);
else */CPU_INT(DMAC_VIF1, g_vif1Cycles /*VifCycleVoodoo*/);
return;
}
if (!vif1.done)
{
@ -318,9 +316,23 @@ __fi void vif1Interrupt()
if ((vif1.inprogress & 0x1) == 0) vif1SetupTransfer();
if (vif1ch.chcr.DIR) vif1Regs.stat.FQC = min(vif1ch.qwc, (u16)16);
CPU_INT(DMAC_VIF1, g_vif1Cycles);
}
if (vif1.inprogress & 0x1)
{
_VIF1chain();
// VIF_NORMAL_FROM_MEM_MODE is a very slow operation.
// Timesplitters 2 depends on this being a bit higher than 128.
if (vif1ch.chcr.DIR) vif1Regs.stat.FQC = min(vif1ch.qwc, (u16)16);
}
if(g_vif1Cycles > 0 || vif1ch.qwc)
{
CPU_INT(DMAC_VIF1, max((int)g_vif1Cycles, 8));
return;
}
else if(vif1Regs.stat.VPS == VPS_TRANSFERRING) DevCon.Warning("Cycles %x, cmd %x, qwc %x, waitonvu %x", g_vif1Cycles, vif1.cmd, vif1ch.qwc, vif1.waitforvu);
if (vif1.vifstalled && vif1.irq)
{
@ -344,7 +356,6 @@ __fi void vif1Interrupt()
vif1ch.chcr.STR = false;
vif1.vifstalled = false;
g_vif1Cycles = 0;
g_vu1Cycles = 0;
DMA_LOG("VIF1 DMA End");
hwDmacIrq(DMAC_VIF1);
@ -364,7 +375,6 @@ void dmaVIF1()
vif1.vifstalled = false;
vif1.inprogress = 0;*/
g_vif1Cycles = 0;
g_vu1Cycles = 0;
#ifdef PCSX2_DEVBUILD
if (dmacRegs.ctrl.STD == STD_VIF1)
@ -410,7 +420,7 @@ void dmaVIF1()
{
vif1.dmamode = VIF_CHAIN_MODE;
vif1.done = false;
vif1.inprogress = 0;
vif1.inprogress &= ~0x1;
}
if (vif1ch.chcr.DIR) vif1Regs.stat.FQC = min((u16)0x10, vif1ch.qwc);

View File

@ -20,10 +20,6 @@
#include "Vif_Dma.h"
u16 vifqwc = 0;
u32 g_vu0Cycles = 0;
u32 g_vu1Cycles = 0;
u32 g_packetsizeonvu0 = 0;
u32 g_packetsizeonvu1 = 0;
static u32 qwctag(u32 mask)
{
@ -267,6 +263,12 @@ void vifMFIFOInterrupt()
return;
}
}
if(vif1.waitforvu == true)
{
// DevCon.Warning("Waiting on VU1 MFIFO");
CPU_INT(DMAC_MFIFO_VIF, 16);
return;
}
// We need to check the direction, if it is downloading from the GS,
// we handle that separately (KH2 for testing)

View File

@ -76,12 +76,28 @@ static __fi void vuExecMicro(int idx, u32 addr) {
if (!idx) vu0ExecMicro(addr);
else vu1ExecMicro(addr);
if (!idx || !THREAD_VU1) {
if (!idx) { g_vu0Cycles += (VU0.cycle-startcycles); g_packetsizeonvu0 = vif0.vifpacketsize; }
else { g_vu1Cycles += (VU1.cycle-startcycles); g_packetsizeonvu1 = vif1.vifpacketsize; }
}
if (!idx) { startcycles = ((VU0.cycle-startcycles) + ( vif0ch.qwc - (vif0.vifpacketsize >> 2) )); CPU_INT(VIF_VU0_FINISH, startcycles * BIAS); }
else { startcycles = ((VU1.cycle-startcycles) + ( vif1ch.qwc - (vif1.vifpacketsize >> 2) )); CPU_INT(VIF_VU1_FINISH, startcycles * BIAS); }
//DevCon.Warning("Ran VU%x, VU0 Cycles %x, VU1 Cycles %x, start %x cycle %x", idx, g_vu0Cycles, g_vu1Cycles, startcycles, VU1.cycle);
GetVifX.vifstalled = true;
//GetVifX.vifstalled = true;
}
void ExecuteVU(int idx)
{
vifStruct& vifX = GetVifX;
if((vifX.cmd & 0x7f) == 0x17)
{
vuExecMicro(idx, -1);
vifX.cmd = 0;
}
else if((vifX.cmd & 0x7f) == 0x14 || (vifX.cmd & 0x7f) == 0x15)
{
vuExecMicro(idx, (u16)(vifXRegs.code) << 3);
vifX.cmd = 0;
}
}
//------------------------------------------------------------------
@ -174,14 +190,14 @@ vifOp(vifCode_FlushA) {
//p3.state= GIF_PATH_IDLE; // Does any game need this anymore?
DevCon.Warning("Vif FlushA - path3 has no more data, but didn't EOP");
}
else { // Path 3 hasn't finished its current gs packet
/*else { // Path 3 hasn't finished its current gs packet
if (gifUnit.stat.APATH != 3 && gifUnit.Path3Masked()) {
gifUnit.stat.APATH = 3; // Hack: Force path 3 to finish (persona 3 needs this)
//DevCon.Warning("Vif FlushA - Forcing path3 to finish current packet");
}
gifInterrupt(); // Feed path3 some gif dma data
gifUnit.Execute(); // Execute path3 in-case gifInterrupt() didn't...
}
}*/
if (p3.state != GIF_PATH_IDLE) {
doStall = true; // If path3 still isn't finished...
}
@ -245,7 +261,7 @@ vifOp(vifCode_MPG) {
int vifNum = (u8)(vifXRegs.code >> 16);
vifX.tag.addr = (u16)(vifXRegs.code << 3) & (idx ? 0x3fff : 0xfff);
vifX.tag.size = vifNum ? (vifNum*2) : 512;
//vifFlush(idx);
vifFlush(idx);
return 1;
}
pass2 {
@ -275,7 +291,15 @@ vifOp(vifCode_MPG) {
vifOp(vifCode_MSCAL) {
vifStruct& vifX = GetVifX;
pass1 { vifFlush(idx); vuExecMicro(idx, (u16)(vifXRegs.code) << 3); vifX.cmd = 0;}
pass1 {
vifFlush(idx);
if(vifX.waitforvu == false)
{
vuExecMicro(idx, (u16)(vifXRegs.code) << 3);
vifX.cmd = 0;
}
}
pass3 { VifCodeLog("MSCAL"); }
return 0;
}
@ -290,7 +314,8 @@ vifOp(vifCode_MSCALF) {
vif1Regs.stat.VGW = true;
vifX.vifstalled = true;
}
else {
if(vifX.waitforvu == false)
{
vuExecMicro(idx, (u16)(vifXRegs.code) << 3);
vifX.cmd = 0;
}
@ -301,7 +326,14 @@ vifOp(vifCode_MSCALF) {
vifOp(vifCode_MSCNT) {
vifStruct& vifX = GetVifX;
pass1 { vifFlush(idx); vuExecMicro(idx, -1); vifX.cmd = 0; }
pass1 {
vifFlush(idx);
if(vifX.waitforvu == false)
{
vuExecMicro(idx, -1);
vifX.cmd = 0;
}
}
pass3 { VifCodeLog("MSCNT"); }
return 0;
}

View File

@ -72,6 +72,7 @@ struct vifStruct {
bool done;
bool vifstalled;
bool stallontag;
bool waitforvu;
// GS registers used for calculating the size of the last local->host transfer initiated on the GS
// Transfer size calculation should be restricted to GS emulation in the future
@ -89,11 +90,13 @@ extern __aligned16 vifStruct vif0, vif1;
_vifT extern u32 vifRead32(u32 mem);
_vifT extern bool vifWrite32(u32 mem, u32 value);
void ExecuteVU(int idx);
extern void vif0Interrupt();
extern void vif0VUFinish();
extern void vif0Reset();
extern void vif1Interrupt();
extern void vif1VUFinish();
extern void vif1Reset();
typedef int __fastcall FnType_VifCmdHandler(int pass, const u32 *data);
@ -119,10 +122,6 @@ static const unsigned int VIF1intc = 5;
extern u32 g_vif0Cycles;
extern u32 g_vif1Cycles;
extern u32 g_vu0Cycles;
extern u32 g_vu1Cycles;
extern u32 g_packetsizeonvu0;
extern u32 g_packetsizeonvu1;
extern void vif0FLUSH();
extern void vif1FLUSH();

View File

@ -122,14 +122,13 @@ _vifT static __fi bool vifTransfer(u32 *data, int size, bool TTE) {
transferred += size - vifX.vifpacketsize;
if (!idx) {
g_packetsizeonvu0 = size;
g_vif0Cycles +=((transferred * BIAS) >> 2) ; /* guessing */
}
else {
g_packetsizeonvu1 = size;
g_vif1Cycles +=((transferred * BIAS) >> 2) ; /* guessing */
}
//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;
@ -138,7 +137,8 @@ _vifT static __fi bool vifTransfer(u32 *data, int size, bool TTE) {
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)

View File

@ -79,7 +79,7 @@ void mVUendProgram(mV, microFlagCycles* mFC, int isEbit) {
if (isEbit || isVU1) { // Clear 'is busy' Flags
if (!mVU.index || !THREAD_VU1) {
xAND(ptr32[&VU0.VI[REG_VPU_STAT].UL], (isVU1 ? ~0x100 : ~0x001)); // VBS0/VBS1 flag
xAND(ptr32[&mVU.getVifRegs().stat], ~VIF1_STAT_VEW); // Clear VU 'is busy' signal for vif
//xAND(ptr32[&mVU.getVifRegs().stat], ~VIF1_STAT_VEW); // Clear VU 'is busy' signal for vif
}
}

View File

@ -232,7 +232,8 @@ INTERPRETATE_COP2_FUNC(CALLMSR);
void _setupBranchTest(u32*(jmpType)(u32), bool isLikely) {
printCOP2("COP2 Branch");
_eeFlushAllUnused();
TEST32ItoM((uptr)&VU0.VI[REG_VPU_STAT].UL, 0x100);
TEST32ItoM((uptr)&vif1Regs.stat._u32, 0x4);
//TEST32ItoM((uptr)&VU0.VI[REG_VPU_STAT].UL, 0x100);
recDoBranchImm(jmpType(0), isLikely);
}

View File

@ -2721,7 +2721,7 @@ static void SuperVURecompile()
pxAssert(pchild->blocks.size() == 0);
AND32ItoM((uptr)&VU0.VI[ REG_VPU_STAT ].UL, s_vu ? ~0x100 : ~0x001); // E flag
AND32ItoM((uptr)&VU->GetVifRegs().stat, ~VIF1_STAT_VEW);
//AND32ItoM((uptr)&VU->GetVifRegs().stat, ~VIF1_STAT_VEW);
MOV32ItoM((uptr)&VU->VI[REG_TPC], pchild->endpc);
JMP32((uptr)SuperVUEndProgram - ((uptr)x86Ptr + 5));
@ -2994,7 +2994,7 @@ void VuBaseBlock::Recompile()
_freeXMMregs();
_freeX86regs();
AND32ItoM((uptr)&VU0.VI[ REG_VPU_STAT ].UL, s_vu ? ~0x100 : ~0x001); // E flag
AND32ItoM((uptr)&VU->GetVifRegs().stat, ~VIF1_STAT_VEW);
//AND32ItoM((uptr)&VU->GetVifRegs().stat, ~VIF1_STAT_VEW);
if (!branch) MOV32ItoM((uptr)&VU->VI[REG_TPC], endpc);