mirror of https://github.com/PCSX2/pcsx2.git
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
This commit is contained in:
parent
8c49587764
commit
d6d781522f
|
@ -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<<i) ) continue;
|
||||
|
||||
if (!(counters[i].mode & 0x80)) continue;
|
||||
if (!counters[i].mode.IsCounting ) continue;
|
||||
|
||||
if((counters[i].mode & 0x3) != 0x3) // don't count hblank sources
|
||||
if(counters[i].mode.ClockSource != 0x3) // don't count hblank sources
|
||||
{
|
||||
s32 change = cpuRegs.cycle - counters[i].sCycleT;
|
||||
if( change < 0 ) change = 0; // sanity check!
|
||||
|
@ -581,107 +604,79 @@ __forceinline void rcntUpdate()
|
|||
cpuRcntSet();
|
||||
}
|
||||
|
||||
void rcntWcount(int index, u32 value)
|
||||
{
|
||||
EECNT_LOG("EE count write %d count %x with %x target %x eecycle %x\n", index, counters[index].count, value, counters[index].target, cpuRegs.eCycle);
|
||||
counters[index].count = value & 0xffff;
|
||||
counters[index].target &= 0xffff;
|
||||
|
||||
if(counters[index].mode & 0x80) {
|
||||
if((counters[index].mode & 0x3) != 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 );
|
||||
}
|
||||
|
||||
static void _rcntSetGate( int index )
|
||||
{
|
||||
if((counters[index].mode & 0xF) == 0x7) {
|
||||
gates &= ~(1<<index);
|
||||
SysPrintf("Counters: Gate Disabled\n");
|
||||
//counters[index].mode &= ~0x80;
|
||||
}
|
||||
else if (counters[index].mode & 0x4) {
|
||||
gates |= (1<<index);
|
||||
counters[index].mode &= ~0x80;
|
||||
rcntReset(index);
|
||||
}
|
||||
else gates &= ~(1<<index);
|
||||
}
|
||||
if (counters[index].mode.EnableGate)
|
||||
{
|
||||
// If the Gate Source is hblank and the clock selection is also hblank
|
||||
// then the gate is disabled and the counter acts as a normal hblank source.
|
||||
|
||||
void rcntWmode(int index, u32 value)
|
||||
{
|
||||
if(counters[index].mode & 0x80) {
|
||||
if((counters[index].mode & 0x3) != 0x3) {
|
||||
if( !(counters[index].mode.GateSource == 0 && counters[index].mode.ClockSource == 3) )
|
||||
{
|
||||
EECNT_LOG( "EE Counter[%d] Using Gate! Source=%s, Mode=%d.\n",
|
||||
index, counters[index].mode.GateSource ? "vblank" : "hblank", counters[index].mode.GateMode );
|
||||
|
||||
u32 change = cpuRegs.cycle - counters[index].sCycleT;
|
||||
if( change > 0 )
|
||||
{
|
||||
counters[index].count += change / counters[index].rate;
|
||||
change -= (change / counters[index].rate) * counters[index].rate;
|
||||
counters[index].sCycleT = cpuRegs.cycle - change;
|
||||
}
|
||||
gates |= (1<<index);
|
||||
counters[index].mode.IsCounting = 0;
|
||||
rcntReset(index);
|
||||
return;
|
||||
}
|
||||
else
|
||||
EECNT_LOG( "EE Counter[%d] GATE DISABLED because of hblank source.\n", index );
|
||||
}
|
||||
else counters[index].sCycleT = cpuRegs.cycle;
|
||||
|
||||
counters[index].mode &= ~(value & 0xc00); //Clear status flags, the ps2 only clears what is given in the value
|
||||
counters[index].mode = (counters[index].mode & 0xc00) | (value & 0x3ff);
|
||||
EECNT_LOG("EE counter set %d mode %x count %x\n", index, counters[index].mode, rcntCycle(index));
|
||||
|
||||
switch (value & 0x3) { //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 );
|
||||
gates &= ~(1<<index);
|
||||
}
|
||||
|
||||
// mode - 0 means hblank source, 8 means vblank source.
|
||||
void rcntStartGate(unsigned int mode, u32 sCycle) {
|
||||
void rcntStartGate(uint mode, u32 sCycle)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i <=3; i++) { //Gates for counters
|
||||
for (i=0; i <=3; i++) {
|
||||
|
||||
if ((mode == 0) && ((counters[i].mode & 0x83) == 0x83))
|
||||
//if ((mode == 0) && ((counters[i].mode & 0x83) == 0x83))
|
||||
if ((mode == 0) && counters[i].mode.IsCounting && (counters[i].mode.ClockSource == 3) )
|
||||
{
|
||||
counters[i].count += HBLANK_COUNTER_SPEED; //Update counters using the hblank as the clock
|
||||
// Update counters using the hblank as the clock. This keeps the hblank source
|
||||
// nicely in sync with the counters and serves as an optimization also, since these
|
||||
// counter won't recieve special rcntUpdate scheduling.
|
||||
|
||||
// Note: Target and overflow tests must be done here since they won't be done
|
||||
// currectly by rcntUpdate (since it's not being scheduled for these counters)
|
||||
|
||||
counters[i].count += HBLANK_COUNTER_SPEED;
|
||||
_cpuTestTarget( i );
|
||||
_cpuTestOverflow( i );
|
||||
}
|
||||
if (!(gates & (1<<i))) continue;
|
||||
if ((counters[i].mode & 0x8) != mode) continue;
|
||||
|
||||
switch (counters[i].mode & 0x30) {
|
||||
case 0x00: //Count When Signal is low (off)
|
||||
if (!(gates & (1<<i))) continue;
|
||||
if (counters[i].mode.GateSource != mode) continue;
|
||||
|
||||
switch (counters[i].mode.GateMode) {
|
||||
case 0x0: //Count When Signal is low (off)
|
||||
|
||||
// Just set the start cycle (sCycleT) -- counting will be done as needed
|
||||
// for events (overflows, targets, mode changes, and the gate off below)
|
||||
|
||||
counters[i].mode |= 0x80;
|
||||
counters[i].mode.IsCounting = 1;
|
||||
counters[i].sCycleT = sCycle;
|
||||
EECNT_LOG("EE Counter[%d] %s StartGate Type0, count = %x\n",
|
||||
mode ? "vblank" : "hblank", i, counters[i].count );
|
||||
break;
|
||||
|
||||
case 0x20: // reset and start counting on vsync end
|
||||
case 0x2: // reset and start counting on vsync end
|
||||
// this is the vsync start so do nothing.
|
||||
break;
|
||||
|
||||
case 0x10: //Reset and start counting on Vsync start
|
||||
case 0x30: //Reset and start counting on Vsync start and end
|
||||
counters[i].mode |= 0x80;
|
||||
case 0x1: //Reset and start counting on Vsync start
|
||||
case 0x3: //Reset and start counting on Vsync start and end
|
||||
counters[i].mode.IsCounting = 1;
|
||||
counters[i].count = 0;
|
||||
counters[i].sCycleT = sCycle;
|
||||
counters[i].target &= 0xffff;
|
||||
counters[i].sCycleT = sCycle;
|
||||
EECNT_LOG("EE Counter[%d] %s StartGate Type%d, count = %x\n",
|
||||
mode ? "vblank" : "hblank", i, counters[i].mode.GateMode, counters[i].count );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -695,42 +690,108 @@ void rcntStartGate(unsigned int mode, u32 sCycle) {
|
|||
}
|
||||
|
||||
// mode - 0 means hblank signal, 8 means vblank signal.
|
||||
void rcntEndGate(unsigned int mode, u32 sCycle) {
|
||||
void rcntEndGate(uint mode, u32 sCycle)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; i <=3; i++) { //Gates for counters
|
||||
if (!(gates & (1<<i))) continue;
|
||||
if ((counters[i].mode & 0x8) != mode) continue;
|
||||
if (counters[i].mode.GateSource != mode) continue;
|
||||
|
||||
switch (counters[i].mode & 0x30) {
|
||||
case 0x00: //Count When Signal is low (off)
|
||||
switch (counters[i].mode.GateMode) {
|
||||
case 0x0: //Count When Signal is low (off)
|
||||
|
||||
// Set the count here. Since the timer is being turned off it's
|
||||
// important to record its count at this point.
|
||||
// important to record its count at this point (it won't be counted by
|
||||
// calls to rcntUpdate).
|
||||
|
||||
counters[i].count = rcntRcount(i);
|
||||
counters[i].mode &= ~0x80;
|
||||
counters[i].mode.IsCounting = 0;
|
||||
counters[i].sCycleT = sCycle;
|
||||
|
||||
break;
|
||||
case 0x10: // Reset and start counting on Vsync start
|
||||
EECNT_LOG("EE Counter[%d] %s EndGate Type0, count = %x\n",
|
||||
mode ? "vblank" : "hblank", i, counters[i].count );
|
||||
break;
|
||||
|
||||
case 0x1: // Reset and start counting on Vsync start
|
||||
// this is the vsync end so do nothing
|
||||
break;
|
||||
case 0x20: //Reset and start counting on Vsync end
|
||||
case 0x30: //Reset and start counting on Vsync start and end
|
||||
counters[i].mode |= 0x80;
|
||||
break;
|
||||
|
||||
case 0x2: //Reset and start counting on Vsync end
|
||||
case 0x3: //Reset and start counting on Vsync start and end
|
||||
counters[i].mode.IsCounting = 1;
|
||||
counters[i].count = 0;
|
||||
counters[i].sCycleT = sCycle;
|
||||
counters[i].target &= 0xffff;
|
||||
break;
|
||||
counters[i].sCycleT = sCycle;
|
||||
EECNT_LOG("EE Counter[%d] %s EndGate Type%d, count = %x\n",
|
||||
mode ? "vblank" : "hblank", i, counters[i].mode.GateMode, counters[i].count );
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Note: No need to set counters here. They'll get set when control returns to
|
||||
// rcntUpdate, since we're being called from there anyway.
|
||||
}
|
||||
|
||||
void rcntWtarget(int index, u32 value) {
|
||||
void rcntWmode(int index, u32 value)
|
||||
{
|
||||
if(counters[index].mode.IsCounting) {
|
||||
if(counters[index].mode.ClockSource != 0x3) {
|
||||
|
||||
u32 change = cpuRegs.cycle - counters[index].sCycleT;
|
||||
if( change > 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;
|
||||
|
|
|
@ -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
|
||||
|
|
34
pcsx2/Hw.cpp
34
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
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue