From d6d781522f6b05a757f1e3f3b0d879c65c7bc728 Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Wed, 7 Jan 2009 22:05:11 +0000 Subject: [PATCH] Fixed Dark Cloud freeze at startup, as per Issue 109. It's not the most ideal fix, but it'll do for now until I can find the proper cause of this erratic behavior in the EE's exception handler. git-svn-id: http://pcsx2-playground.googlecode.com/svn/trunk@561 a6443dda-0b58-4228-96e9-037be469359c --- pcsx2/Counters.cpp | 297 +++++++++++++++++++++++++----------------- pcsx2/Counters.h | 53 +++++++- pcsx2/Hw.cpp | 34 ++--- pcsx2/InterTables.cpp | 10 +- pcsx2/PsxCounters.cpp | 64 ++++----- pcsx2/R5900.cpp | 47 ++++--- 6 files changed, 321 insertions(+), 184 deletions(-) diff --git a/pcsx2/Counters.cpp b/pcsx2/Counters.cpp index a4ed37e00d..37218b16c2 100644 --- a/pcsx2/Counters.cpp +++ b/pcsx2/Counters.cpp @@ -61,7 +61,7 @@ static __forceinline void _rcntSet( int i ) assert( i <= 4 ); // rcntSet isn't valid for h/vsync counters. // Stopped or special hsync gate? - if (!(counters[i].mode & 0x80) || (counters[i].mode & 0x3) == 0x3) return; + if (!counters[i].mode.IsCounting || (counters[i].mode.ClockSource == 0x3) ) return; // nextCounter is relative to the cpuRegs.cycle when rcntUpdate() was last called. // However, the current _rcntSet could be called at any cycle count, so we need to take @@ -111,9 +111,9 @@ void rcntInit() { counters[2].interrupt = 11; counters[3].interrupt = 12; - counters[4].mode = MODE_HRENDER; + counters[4].modeval = MODE_HRENDER; counters[4].sCycle = cpuRegs.cycle; - counters[5].mode = MODE_VRENDER; + counters[5].modeval = MODE_VRENDER; counters[5].sCycle = cpuRegs.cycle; UpdateVSyncRate(); @@ -393,6 +393,7 @@ static __forceinline void frameLimit() static __forceinline void VSyncStart(u32 sCycle) { + EECNT_LOG( "//////// EE COUNTER VSYNC START \\\\\\\\ (frame: %d)\n", iFrame ); vSyncDebugStuff(); // EE Profiling and Debug code if ((CSRw & 0x8)) GSCSRr|= 0x8; @@ -404,11 +405,28 @@ static __forceinline void VSyncStart(u32 sCycle) if (gates) rcntStartGate(0x8, sCycle); // Counters Start Gate code if (Config.Patch) applypatch(1); // Apply patches (ToDo: clean up patch code) - cpuRegs.eCycle[30] = 8; + // INTC - VB Blank Start Hack -- + // Hack fix! This corrects a freezeup in Granda 2 where it decides to spin + // on the INTC_STAT register after the exception handler has already cleared + // it. But be warned! Set the value to larger than 4 and it breaks Dark + // Cloud and other games. -_- + + // How it works: Normally the INTC raises exceptions immediately at the end of the + // current branch test. But in the case of Grandia 2, the game's code is spinning + // on the INTC status, and the exception handler (for some reason?) clears the INTC + // before returning *and* returns to a location other than EPC. So the game never + // gets to the point where it sees the INTC Irq set true. + + // (I haven't investigated why Dark Cloud freezes on larger values) + // (all testing done using the recompiler -- dunno how the ints respond yet) + + cpuRegs.eCycle[30] = 2; } static __forceinline void VSyncEnd(u32 sCycle) { + EECNT_LOG( "//////// EE COUNTER VSYNC END \\\\\\\\ (frame: %d)\n", iFrame ); + iFrame++; if( g_vu1SkipCount > 0 ) @@ -427,6 +445,10 @@ static __forceinline void VSyncEnd(u32 sCycle) psxVBlankEnd(); // psxCounters vBlank End if (gates) rcntEndGate(0x8, sCycle); // Counters End Gate Code frameLimit(); // limit FPS + + // This doesn't seem to be needed here. Games only seem to break with regard to the + // vsyncstart irq. + //cpuRegs.eCycle[30] = 2; } //#define VSYNC_DEBUG // Uncomment this to enable some vSync Timer debugging features. @@ -440,14 +462,14 @@ __forceinline void rcntUpdate_hScanline() if( !cpuTestCycle( counters[4].sCycle, counters[4].CycleT ) ) return; //iopBranchAction = 1; - if (counters[4].mode & MODE_HBLANK) { //HBLANK Start + if (counters[4].modeval & MODE_HBLANK) { //HBLANK Start rcntStartGate(0, counters[4].sCycle); psxCheckStartGate16(0); // Setup the hRender's start and end cycle information: counters[4].sCycle += vSyncInfo.hBlank; // start (absolute cycle value) counters[4].CycleT = vSyncInfo.hRender; // endpoint (delta from start value) - counters[4].mode = MODE_HRENDER; + counters[4].modeval = MODE_HRENDER; } else { //HBLANK END / HRENDER Begin if (CSRw & 0x4) GSCSRr |= 4; // signal @@ -458,7 +480,7 @@ __forceinline void rcntUpdate_hScanline() // set up the hblank's start and end cycle information: counters[4].sCycle += vSyncInfo.hRender; // start (absolute cycle value) counters[4].CycleT = vSyncInfo.hBlank; // endpoint (delta from start value) - counters[4].mode = MODE_HBLANK; + counters[4].modeval = MODE_HBLANK; # ifdef VSYNC_DEBUG hsc++; @@ -472,13 +494,13 @@ __forceinline void rcntUpdate_vSync() if( diff < counters[5].CycleT ) return; //iopBranchAction = 1; - if (counters[5].mode == MODE_VSYNC) + if (counters[5].modeval == MODE_VSYNC) { VSyncEnd(counters[5].sCycle); counters[5].sCycle += vSyncInfo.Blank; counters[5].CycleT = vSyncInfo.Render; - counters[5].mode = MODE_VRENDER; + counters[5].modeval = MODE_VRENDER; SysUpdate(); // check for and handle keyevents } @@ -488,7 +510,7 @@ __forceinline void rcntUpdate_vSync() counters[5].sCycle += vSyncInfo.Render; counters[5].CycleT = vSyncInfo.Blank; - counters[5].mode = MODE_VSYNC; + counters[5].modeval = MODE_VSYNC; // Accumulate hsync rounding errors: counters[4].sCycle += vSyncInfo.hSyncError; @@ -511,16 +533,17 @@ static __forceinline void __fastcall _cpuTestTarget( int i ) { if (counters[i].count < counters[i].target) return; - if(counters[i].mode & 0x100) { + if(counters[i].mode.TargetInterrupt) { - EECNT_LOG("EE counter %d target reached mode %x count %x target %x\n", i, counters[i].mode, counters[i].count, counters[i].target); - counters[i].mode|= 0x0400; // Equal Target flag + EECNT_LOG("EE Counter[%d] TARGET reached - mode=%x, count=%x, target=%x\n", i, counters[i].mode, counters[i].count, counters[i].target); + counters[i].mode.TargetReached = 1; hwIntcIrq(counters[i].interrupt); - if (counters[i].mode & 0x40) { //The PS2 only resets if the interrupt is enabled - Tested on PS2 + // The PS2 only resets if the interrupt is enabled - Tested on PS2 + if (counters[i].mode.ZeroReturn) counters[i].count -= counters[i].target; // Reset on target - } - else counters[i].target |= 0x10000000; + else + counters[i].target |= 0x10000000; } else counters[i].target |= 0x10000000; } @@ -529,9 +552,9 @@ static __forceinline void _cpuTestOverflow( int i ) { if (counters[i].count <= 0xffff) return; - if (counters[i].mode & 0x0200) { // Overflow interrupt - EECNT_LOG("EE counter %d overflow mode %x count %x target %x\n", i, counters[i].mode, counters[i].count, counters[i].target); - counters[i].mode |= 0x0800; // Overflow flag + if (counters[i].mode.OverflowInterrupt) { + EECNT_LOG("EE Counter[%d] OVERFLOW - mode=%x, count=%x\n", i, counters[i].mode, counters[i].count); + counters[i].mode.OverflowReached = 1; hwIntcIrq(counters[i].interrupt); } @@ -559,9 +582,9 @@ __forceinline void rcntUpdate() //if ( gates & (1< 0 ) { - change -= (change / counters[index].rate) * counters[index].rate; - counters[index].sCycleT = cpuRegs.cycle - change; - } - } - } - else counters[index].sCycleT = cpuRegs.cycle; - - _rcntSet( index ); -} - static void _rcntSetGate( int index ) { - if((counters[index].mode & 0xF) == 0x7) { - gates &= ~(1< 0 ) - { - counters[index].count += change / counters[index].rate; - change -= (change / counters[index].rate) * counters[index].rate; - counters[index].sCycleT = cpuRegs.cycle - change; - } + gates |= (1< 0 ) + { + counters[index].count += change / counters[index].rate; + change -= (change / counters[index].rate) * counters[index].rate; + counters[index].sCycleT = cpuRegs.cycle - change; + } + } + } + else counters[index].sCycleT = cpuRegs.cycle; + + counters[index].modeval &= ~(value & 0xc00); //Clear status flags, the ps2 only clears what is given in the value + counters[index].modeval = (counters[index].modeval & 0xc00) | (value & 0x3ff); + EECNT_LOG("EE Counter[%d] writeMode = %x passed value=%x\n", index, counters[index].modeval, value ); + + switch (counters[index].mode.ClockSource) { //Clock rate divisers *2, they use BUSCLK speed not PS2CLK + case 0: counters[index].rate = 2; break; + case 1: counters[index].rate = 32; break; + case 2: counters[index].rate = 512; break; + case 3: counters[index].rate = vSyncInfo.hBlank+vSyncInfo.hRender; break; + } + + _rcntSetGate( index ); + _rcntSet( index ); +} + +void rcntWcount(int index, u32 value) +{ + EECNT_LOG("EE Counter[%d] writeCount = %x, oldcount=%x, target=%x\n", index, value, counters[index].count, counters[index].target ); + + counters[index].count = value & 0xffff; + + // reset the target, and make sure we don't get a premature target. + counters[index].target &= 0xffff; + if( counters[index].count > counters[index].target ) + counters[index].target |= 0x10000000; + + // re-calculate the start cycle of the counter based on elapsed time since the last counter update: + if(counters[index].mode.IsCounting) { + if(counters[index].mode.ClockSource != 0x3) { + s32 change = cpuRegs.cycle - counters[index].sCycleT; + if( change > 0 ) { + change -= (change / counters[index].rate) * counters[index].rate; + counters[index].sCycleT = cpuRegs.cycle - change; + } + } + } + else counters[index].sCycleT = cpuRegs.cycle; + + _rcntSet( index ); +} + +void rcntWtarget(int index, u32 value) +{ + EECNT_LOG("EE Counter[%d] writeTarget = %x\n", index, value); - EECNT_LOG("EE target write %d target %x value %x\n", index, counters[index].target, value); counters[index].target = value & 0xffff; // guard against premature (instant) targeting. @@ -743,27 +804,29 @@ void rcntWtarget(int index, u32 value) { _rcntSet( index ); } -void rcntWhold(int index, u32 value) { - EECNT_LOG("EE hold write %d value %x\n", index, value); +void rcntWhold(int index, u32 value) +{ + EECNT_LOG("EE Counter[%d] Hold Write = %x\n", index, value); counters[index].hold = value; } -u32 rcntRcount(int index) { +u32 rcntRcount(int index) +{ u32 ret; // only count if the counter is turned on (0x80) and is not an hsync gate (!0x03) - if ((counters[index].mode & 0x80) && ((counters[index].mode & 0x3) != 0x3)) + if (counters[index].mode.IsCounting && (counters[index].mode.ClockSource != 0x3)) ret = counters[index].count + ((cpuRegs.cycle - counters[index].sCycleT) / counters[index].rate); else ret = counters[index].count; - EECNT_LOG("EE count read %d value %x\n", index, ret); + EECNT_LOG("EE Counter[%d] readCount32 = %x\n", index, ret); return ret; } -u32 rcntCycle(int index) { - - if ((counters[index].mode & 0x80) && ((counters[index].mode & 0x3) != 0x3)) +u32 rcntCycle(int index) +{ + if (counters[index].mode.IsCounting && (counters[index].mode.ClockSource != 0x3)) return counters[index].count + ((cpuRegs.cycle - counters[index].sCycleT) / counters[index].rate); else return counters[index].count; diff --git a/pcsx2/Counters.h b/pcsx2/Counters.h index 93b596cb02..bf0d79b400 100644 --- a/pcsx2/Counters.h +++ b/pcsx2/Counters.h @@ -19,10 +19,61 @@ #ifndef __COUNTERS_H__ #define __COUNTERS_H__ +struct EECNT_MODE +{ + // 0 - BUSCLK + // 1 - 1/16th of BUSCLK + // 2 - 1/256th of BUSCLK + // 3 - External Clock (hblank!) + u32 ClockSource:2; + + // Enables the counter gate (turns counter on/off as according to the + // h/v blank type set in GateType). + u32 EnableGate:1; + + // 0 - hblank! 1 - vblank! + // Note: the hblank source type is disabled when ClockSel = 3 + u32 GateSource:1; + + // 0 - count when the gate signal is low + // 1 - reset and start counting at the signal's rising edge (h/v blank end) + // 2 - reset and start counting at the signal's falling edge (h/v blank start) + // 3 - reset and start counting at both signal edges + u32 GateMode:2; + + // Counter cleared to zero when target reached. + // The PS2 only resets if the TargetInterrupt is enabled - Tested on PS2 + u32 ZeroReturn:1; + + // General count enable/status. If 0, no counting happens. + // This flag is set/unset by the gates. + u32 IsCounting:1; + + // Enables target interrupts. + u32 TargetInterrupt:1; + + // Enables overflow interrupts. + u32 OverflowInterrupt:1; + + // Set to true by the counter when the target is reached. + // Flag is set only when TargetInterrupt is enabled. + u32 TargetReached:1; + + // Set to true by the counter when the target has overflowed. + // Flag is set only when OverflowInterrupt is enabled. + u32 OverflowReached:1; +}; + // fixme: Cycle and sCycleT members are unused. // But they can't be removed without making a new savestate version. struct Counter { - u32 count, mode, target, hold; + u32 count; + union + { + u32 modeval; // the mode as a 32 bit int (for optimized combination masks) + EECNT_MODE mode; + }; + u32 target, hold; u32 rate, interrupt; u32 Cycle; u32 sCycle; // start cycle of timer diff --git a/pcsx2/Hw.cpp b/pcsx2/Hw.cpp index 62b65716a8..f77678391a 100644 --- a/pcsx2/Hw.cpp +++ b/pcsx2/Hw.cpp @@ -124,21 +124,21 @@ u16 hwRead16(u32 mem) switch (mem) { case 0x10000000: ret = (u16)rcntRcount(0); break; - case 0x10000010: ret = (u16)counters[0].mode; break; + case 0x10000010: ret = (u16)counters[0].modeval; break; case 0x10000020: ret = (u16)counters[0].target; break; case 0x10000030: ret = (u16)counters[0].hold; break; case 0x10000800: ret = (u16)rcntRcount(1); break; - case 0x10000810: ret = (u16)counters[1].mode; break; + case 0x10000810: ret = (u16)counters[1].modeval; break; case 0x10000820: ret = (u16)counters[1].target; break; case 0x10000830: ret = (u16)counters[1].hold; break; case 0x10001000: ret = (u16)rcntRcount(2); break; - case 0x10001010: ret = (u16)counters[2].mode; break; + case 0x10001010: ret = (u16)counters[2].modeval; break; case 0x10001020: ret = (u16)counters[2].target; break; case 0x10001800: ret = (u16)rcntRcount(3); break; - case 0x10001810: ret = (u16)counters[3].mode; break; + case 0x10001810: ret = (u16)counters[3].modeval; break; case 0x10001820: ret = (u16)counters[3].target; break; default: @@ -173,21 +173,21 @@ u32 hwRead32(u32 mem) { // gauntlen uses 0x1001xxxx switch (mem) { case 0x10000000: return (u16)rcntRcount(0); - case 0x10000010: return (u16)counters[0].mode; + case 0x10000010: return (u16)counters[0].modeval; case 0x10000020: return (u16)counters[0].target; case 0x10000030: return (u16)counters[0].hold; case 0x10000800: return (u16)rcntRcount(1); - case 0x10000810: return (u16)counters[1].mode; + case 0x10000810: return (u16)counters[1].modeval; case 0x10000820: return (u16)counters[1].target; case 0x10000830: return (u16)counters[1].hold; case 0x10001000: return (u16)rcntRcount(2); - case 0x10001010: return (u16)counters[2].mode; + case 0x10001010: return (u16)counters[2].modeval; case 0x10001020: return (u16)counters[2].target; case 0x10001800: return (u16)rcntRcount(3); - case 0x10001810: return (u16)counters[3].mode; + case 0x10001810: return (u16)counters[3].modeval; case 0x10001820: return (u16)counters[3].target; #ifdef PCSX2_DEVBUILD @@ -386,25 +386,25 @@ void hwWrite8(u32 mem, u8 value) { switch (mem) { case 0x10000000: rcntWcount(0, value); break; - case 0x10000010: rcntWmode(0, (counters[0].mode & 0xff00) | value); break; - case 0x10000011: rcntWmode(0, (counters[0].mode & 0xff) | value << 8); break; + case 0x10000010: rcntWmode(0, (counters[0].modeval & 0xff00) | value); break; + case 0x10000011: rcntWmode(0, (counters[0].modeval & 0xff) | value << 8); break; case 0x10000020: rcntWtarget(0, value); break; case 0x10000030: rcntWhold(0, value); break; case 0x10000800: rcntWcount(1, value); break; - case 0x10000810: rcntWmode(1, (counters[1].mode & 0xff00) | value); break; - case 0x10000811: rcntWmode(1, (counters[1].mode & 0xff) | value << 8); break; + case 0x10000810: rcntWmode(1, (counters[1].modeval & 0xff00) | value); break; + case 0x10000811: rcntWmode(1, (counters[1].modeval & 0xff) | value << 8); break; case 0x10000820: rcntWtarget(1, value); break; case 0x10000830: rcntWhold(1, value); break; case 0x10001000: rcntWcount(2, value); break; - case 0x10001010: rcntWmode(2, (counters[2].mode & 0xff00) | value); break; - case 0x10001011: rcntWmode(2, (counters[2].mode & 0xff) | value << 8); break; + case 0x10001010: rcntWmode(2, (counters[2].modeval & 0xff00) | value); break; + case 0x10001011: rcntWmode(2, (counters[2].modeval & 0xff) | value << 8); break; case 0x10001020: rcntWtarget(2, value); break; case 0x10001800: rcntWcount(3, value); break; - case 0x10001810: rcntWmode(3, (counters[3].mode & 0xff00) | value); break; - case 0x10001811: rcntWmode(3, (counters[3].mode & 0xff) | value << 8); break; + case 0x10001810: rcntWmode(3, (counters[3].modeval & 0xff00) | value); break; + case 0x10001811: rcntWmode(3, (counters[3].modeval & 0xff) | value << 8); break; case 0x10001820: rcntWtarget(3, value); break; case 0x1000f180: @@ -939,7 +939,7 @@ void hwWrite32(u32 mem, u32 value) { case 0x1000f000: // INTC_STAT HW_LOG("INTC_STAT Write 32bit %x\n", value); psHu32(0xf000)&=~value; - cpuTestINTCInts(); + //cpuTestINTCInts(); break; case 0x1000f010: // INTC_MASK diff --git a/pcsx2/InterTables.cpp b/pcsx2/InterTables.cpp index e027f10ed9..a77204cc95 100644 --- a/pcsx2/InterTables.cpp +++ b/pcsx2/InterTables.cpp @@ -37,9 +37,11 @@ namespace EE static const int Cycles_MMI_Mult = 3*8; static const int Cycles_MMI_Div = 22*8; - static const int Cycles_Store = 21; // 21 for snes emu + static const int Cycles_Store = 20; // 21 for snes emu static const int Cycles_Load = 11; // 13 for snes emu + static const int Cycles_Misc = 7; + MakeOpcode( Unknown, Default ); MakeOpcode( MMI_Unknown, Default ); @@ -59,9 +61,9 @@ namespace EE // Misc Junk - MakeOpcode( COP0, Default ); - MakeOpcode( COP1, Default ); - MakeOpcode( COP2, Default ); + MakeOpcode( COP0, Misc ); + MakeOpcode( COP1, Misc ); + MakeOpcode( COP2, Misc ); MakeOpcode( CACHE, Default ); MakeOpcode( PREF, Default ); diff --git a/pcsx2/PsxCounters.cpp b/pcsx2/PsxCounters.cpp index 469b7a67cf..a0afa99076 100644 --- a/pcsx2/PsxCounters.cpp +++ b/pcsx2/PsxCounters.cpp @@ -55,31 +55,36 @@ static void psxRcntReset(int index) psxCounters[index].sCycleT = psxRegs.cycle; } -__forceinline static void _rcntSet( int i ) +static void _rcntSet( int cntidx ) { - // thanks to being forceinline'd, this conditional will always be optimized - // to a constant by VC (confirmed via disassembler): - - u64 overflowCap = (i>=3) ? 0x100000000ULL : 0x10000; + u64 overflowCap = (cntidx>=3) ? 0x100000000ULL : 0x10000; u64 c; + const psxCounter& counter = psxCounters[cntidx]; + // psxNextCounter is relative to the psxRegs.cycle when rcntUpdate() was last called. // However, the current _rcntSet could be called at any cycle count, so we need to take // that into account. Adding the difference from that cycle count to the current one // will do the trick! - if( psxCounters[i].mode & IOPCNT_STOPPED || psxCounters[i].rate == PSXHBLANK) return; + if( counter.mode & IOPCNT_STOPPED || counter.rate == PSXHBLANK) return; - c = (u64)((overflowCap - psxCounters[i].count) * psxCounters[i].rate) - (psxRegs.cycle - psxCounters[i].sCycleT); + if( counter.count > overflowCap || counter.count > counter.target ) + { + psxNextCounter = 4; + return; + } + + c = (u64)((overflowCap - counter.count) * counter.rate) - (psxRegs.cycle - counter.sCycleT); c += psxRegs.cycle - psxNextsCounter; // adjust for time passed since last rcntUpdate(); - if((u64)c < (u64)psxNextCounter) psxNextCounter = (u32)c; + if(c < (u64)psxNextCounter) psxNextCounter = (u32)c; - //if((psxCounters[i].mode & 0x10) == 0 || psxCounters[i].target > 0xffff) continue; - if( psxCounters[i].target & IOPCNT_FUTURE_TARGET ) return; + //if((counter.mode & 0x10) == 0 || psxCounters[i].target > 0xffff) continue; + if( counter.target & IOPCNT_FUTURE_TARGET ) return; - c = (u64)((psxCounters[i].target - psxCounters[i].count) * psxCounters[i].rate) - (psxRegs.cycle - psxCounters[i].sCycleT); + c = (s64)((counter.target - counter.count) * counter.rate) - (psxRegs.cycle - counter.sCycleT); c += psxRegs.cycle - psxNextsCounter; // adjust for time passed since last rcntUpdate(); - if((u64)c < (u64)psxNextCounter) psxNextCounter = (u32)c; + if(c < (u64)psxNextCounter) psxNextCounter = (u32)c; } @@ -441,7 +446,7 @@ void psxRcntWcount16(int index, u32 value) u32 change; assert( index < 3 ); - PSXCNT_LOG("IOP Counter[%d] > writeCount16 = %x\n", index, value); + PSXCNT_LOG("IOP Counter[%d] writeCount16 = %x\n", index, value); if(psxCounters[index].rate != PSXHBLANK) { @@ -462,7 +467,7 @@ void psxRcntWcount32(int index, u32 value) u32 change; assert( index >= 3 && index < 6 ); - PSXCNT_LOG("IOP Counter[%d] > writeCount32 = %x\n", index, value); + PSXCNT_LOG("IOP Counter[%d] writeCount32 = %x\n", index, value); if(psxCounters[index].rate != PSXHBLANK) { @@ -480,7 +485,7 @@ void psxRcntWcount32(int index, u32 value) void psxRcnt0Wmode(u32 value) { - PSXCNT_LOG("IOP Counter[0] > writeMode = %lx\n", value); + PSXCNT_LOG("IOP Counter[0] writeMode = %lx\n", value); psxCounters[0].mode = value; psxCounters[0].mode|= 0x0400; @@ -492,7 +497,7 @@ void psxRcnt0Wmode(u32 value) if(psxCounters[0].mode & IOPCNT_ENABLE_GATE) { // gated counters are added up as per the h/vblank timers. - PSXCNT_LOG("IOP Counter[0] > Gate Check set, value = %x\n", value); + PSXCNT_LOG("IOP Counter[0] Gate Check set, value = %x\n", value); psxhblankgate |= 1; } else psxhblankgate &= ~1; @@ -506,7 +511,7 @@ void psxRcnt0Wmode(u32 value) void psxRcnt1Wmode(u32 value) { - PSXCNT_LOG("IOP Counter[0] > writeMode = %lx\n", value); + PSXCNT_LOG("IOP Counter[0] writeMode = %lx\n", value); psxCounters[1].mode = value; psxCounters[1].mode|= 0x0400; @@ -517,7 +522,7 @@ void psxRcnt1Wmode(u32 value) if(psxCounters[1].mode & IOPCNT_ENABLE_GATE) { - PSXCNT_LOG("IOP Counter[1] > Gate Check set, value = %x\n", value); + PSXCNT_LOG("IOP Counter[1] Gate Check set, value = %x\n", value); psxvblankgate |= 1<<1; } else psxvblankgate &= ~(1<<1); @@ -530,7 +535,7 @@ void psxRcnt1Wmode(u32 value) void psxRcnt2Wmode(u32 value) { - PSXCNT_LOG("IOP Counter[0] > writeMode = %lx\n", value); + PSXCNT_LOG("IOP Counter[0] writeMode = %lx\n", value); psxCounters[2].mode = value; psxCounters[2].mode|= 0x0400; @@ -555,7 +560,7 @@ void psxRcnt2Wmode(u32 value) void psxRcnt3Wmode(u32 value) { - PSXCNT_LOG("IOP Counter[3] > writeMode = %lx\n", value); + PSXCNT_LOG("IOP Counter[3] writeMode = %lx\n", value); psxCounters[3].mode = value; psxCounters[3].rate = 1; @@ -566,7 +571,7 @@ void psxRcnt3Wmode(u32 value) if(psxCounters[3].mode & IOPCNT_ENABLE_GATE) { - PSXCNT_LOG("IOP Counter[3] > Gate Check set, value = %x\n", value); + PSXCNT_LOG("IOP Counter[3] Gate Check set, value = %x\n", value); psxvblankgate |= 1<<3; } else psxvblankgate &= ~(1<<3); @@ -579,7 +584,7 @@ void psxRcnt3Wmode(u32 value) void psxRcnt4Wmode(u32 value) { - PSXCNT_LOG("IOP Counter[4] > writeMode = %lx\n", value); + PSXCNT_LOG("IOP Counter[4] writeMode = %lx\n", value); psxCounters[4].mode = value; psxCounters[4].mode|= 0x0400; @@ -606,7 +611,7 @@ void psxRcnt4Wmode(u32 value) void psxRcnt5Wmode(u32 value) { - PSXCNT_LOG("IOP Counter[5] > writeMode = %lx\n", value); + PSXCNT_LOG("IOP Counter[5] writeMode = %lx\n", value); psxCounters[5].mode = value; psxCounters[5].mode|= 0x0400; @@ -634,7 +639,7 @@ void psxRcnt5Wmode(u32 value) void psxRcntWtarget16(int index, u32 value) { assert( index < 3 ); - PSXCNT_LOG("IOP Counter[%d] > writeTarget16 = %lx\n", index, value); + PSXCNT_LOG("IOP Counter[%d] writeTarget16 = %lx\n", index, value); psxCounters[index].target = value & 0xffff; // protect the target from an early arrival. @@ -650,7 +655,7 @@ void psxRcntWtarget16(int index, u32 value) void psxRcntWtarget32(int index, u32 value) { assert( index >= 3 && index < 6); - PSXCNT_LOG("IOP Counter[%d] > writeTarget32 = %lx\n", index, value); + PSXCNT_LOG("IOP Counter[%d] writeTarget32 = %lx\n", index, value); psxCounters[index].target = value; @@ -670,7 +675,7 @@ u16 psxRcntRcount16(int index) assert( index < 3 ); - PSXCNT_LOG("IOP Counter[%d] > readCount16 = %lx\n", index, (u16)retval ); + PSXCNT_LOG("IOP Counter[%d] readCount16 = %lx\n", index, (u16)retval ); // Don't count HBLANK timers // Don't count stopped gates either. @@ -680,9 +685,8 @@ u16 psxRcntRcount16(int index) { u32 delta = (u32)((psxRegs.cycle - psxCounters[index].sCycleT) / psxCounters[index].rate); retval += delta; - PSXCNT_LOG(" > (delta = %lx)\n", delta ); + PSXCNT_LOG(" (delta = %lx)\n", delta ); } - PSXCNT_LOG( "\n" ); return (u16)retval; } @@ -693,14 +697,14 @@ u32 psxRcntRcount32(int index) assert( index >= 3 && index < 6 ); - PSXCNT_LOG("IOP Counter[%d] > readCount32 = %lx\n", index, retval ); + PSXCNT_LOG("IOP Counter[%d] readCount32 = %lx\n", index, retval ); if( !( psxCounters[index].mode & IOPCNT_STOPPED ) && ( psxCounters[index].rate != PSXHBLANK ) ) { u32 delta = (u32)((psxRegs.cycle - psxCounters[index].sCycleT) / psxCounters[index].rate); retval += delta; - PSXCNT_LOG(" > (delta = %lx)\n", delta ); + PSXCNT_LOG(" (delta = %lx)\n", delta ); } return retval; diff --git a/pcsx2/R5900.cpp b/pcsx2/R5900.cpp index f6e0ceedbb..11ced7e831 100644 --- a/pcsx2/R5900.cpp +++ b/pcsx2/R5900.cpp @@ -214,7 +214,7 @@ void cpuException(u32 code, u32 bd) { } } else { offset = 0x180; //Overrride the cause - Console::Notice("cpuException: Status.EXL = 1 cause %x", params code); + //Console::Notice("cpuException: Status.EXL = 1 cause %x", params code); } if (cpuRegs.CP0.n.Status.b.BEV == 0) { cpuRegs.pc = 0x80000000 + offset; @@ -246,6 +246,7 @@ void cpuException(u32 code, u32 bd) { offset = 0x180; //Overrride the cause Console::Notice("cpuException: Status.EXL = 1 cause %x", params code); } + if (cpuRegs.CP0.n.Status.b.DEV == 0) { cpuRegs.pc = 0x80000000 + offset; } else { @@ -476,6 +477,17 @@ static __forceinline void _cpuTestPERF() } } +// Checks the COP0.Status for exception enablings. +// Exception handling for certain modes is *not* currently supported, this function filters +// them out. Exceptions while the exception handler is active (EIE), or exceptions of any +// level other than 0 are ignored here. + +static bool cpuIntsEnabled() +{ + return cpuRegs.CP0.n.Status.b.EIE && cpuRegs.CP0.n.Status.b.IE && + !cpuRegs.CP0.n.Status.b.EXL && (cpuRegs.CP0.n.Status.b.ERL == 0); +} + // if cpuRegs.cycle is greater than this cycle, should check cpuBranchTest for updates u32 g_nextBranchCycle = 0; @@ -505,8 +517,9 @@ static __forceinline void _cpuBranchTest_Shared() _cpuTestTIMR(); // ---- Interrupts ------------- + // Handles all interrupts except 30 and 31, which are handled later. - if( cpuRegs.interrupt ) + if( cpuRegs.interrupt & ~(3<<30) ) _cpuTestInterrupts(); // ---- IOP ------------- @@ -517,11 +530,6 @@ static __forceinline void _cpuBranchTest_Shared() // // * The IOP cannot always be run. If we run IOP code every time through the // cpuBranchTest, the IOP generally starts to run way ahead of the EE. - // - // * However! The IOP should be run during certain important events: vsync/hsync - // events and IOP interrupts / exceptions -- even if it's already getting - // a little ahead of the EE. the iopBranchAction global will flag true if - // something like that happens. psxBranchTest(); @@ -530,14 +538,19 @@ static __forceinline void _cpuBranchTest_Shared() //if( EEsCycle < -450 ) // Console::WriteLn( " IOP ahead by: %d cycles", params -EEsCycle ); + // Experimental and Probably Unnecessry Logic --> // Check if the EE already has an exception pending, and if so we shouldn't - // waste too much time updating the IOP. + // waste too much time updating the IOP. Theory being that the EE and IOP should + // run closely in sync during raised exception events. But in practice it didn't + // seem to make much of a difference. // Note: The IOP is very good about chaining blocks together so it tends to - // run lots of cycles, even with only 32 (4 IOP) cycles specified here. + // run lots of cycles, even with only 32 (4 IOP) cycles specified here. That's + // probably why it doesn't improve sync much. - bool eeExceptPending = - ( (cpuRegs.CP0.n.Status.val & 0x10007) == 0x10001 ) && + /*bool eeExceptPending = cpuIntsEnabled() && + //( cpuRegs.CP0.n.Status.b.EIE && cpuRegs.CP0.n.Status.b.IE && (cpuRegs.CP0.n.Status.b.ERL == 0) ) && + //( (cpuRegs.CP0.n.Status.val & 0x10007) == 0x10001 ) && ( (cpuRegs.interrupt & (3<<30)) != 0 ); if( eeExceptPending ) @@ -549,7 +562,7 @@ static __forceinline void _cpuBranchTest_Shared() EEsCycle -= cyclesRun; //Console::Notice( "IOP Exception-Pending Execution -- EEsCycle: %d", params EEsCycle ); } - else + else*/ { EEsCycle = psxCpu->ExecuteBlock( EEsCycle ); } @@ -579,7 +592,9 @@ static __forceinline void _cpuBranchTest_Shared() if( EEsCycle > 192 ) { - // EE's running way ahead of the IOP still, so we should branch quickly. + // EE's running way ahead of the IOP still, so we should branch quickly to give the + // IOP extra timeslices in short order. + cpuSetNextBranchDelta( 48 ); //Console::Notice( "EE ahead of the IOP -- Rapid Branch! %d", params EEsCycle ); } @@ -601,7 +616,8 @@ static __forceinline void _cpuBranchTest_Shared() // This should be done last since the IOP and the VU0 can raise several EE // exceptions. - if ((cpuRegs.CP0.n.Status.val & 0x10007) == 0x10001) + //if ((cpuRegs.CP0.n.Status.val & 0x10007) == 0x10001) + if( cpuIntsEnabled() ) { TESTINT(30, intcInterrupt); TESTINT(31, dmacInterrupt); @@ -661,7 +677,8 @@ __forceinline void CPU_INT( u32 n, s32 ecycle) void cpuTestINTCInts() { if( cpuRegs.interrupt & (1 << 30) ) return; - if( (cpuRegs.CP0.n.Status.val & 0x10407) != 0x10401 ) return; + //if( (cpuRegs.CP0.n.Status.val & 0x10407) != 0x10401 ) return; + if( !cpuIntsEnabled() ) return; if( (psHu32(INTC_STAT) & psHu32(INTC_MASK)) == 0 ) return; cpuRegs.interrupt|= 1 << 30;