diff --git a/plugins/spu2-x/src/Dma.cpp b/plugins/spu2-x/src/Dma.cpp index 0b11a44828..dfc1011c1c 100644 --- a/plugins/spu2-x/src/Dma.cpp +++ b/plugins/spu2-x/src/Dma.cpp @@ -128,15 +128,15 @@ void V_Core::StartADMAWrite(u16 *pMem, u32 sz) if(MsgAutoDMA()) ConLog(" * SPU2: DMA%c AutoDMA Transfer of %d bytes to %x (%02x %x %04x).\n", GetDmaIndexChar(), size<<1, TSA, DMABits, AutoDMACtrl, (~Regs.ATTR)&0x7fff); - InputDataProgress=0; + InputDataProgress = 0; if((AutoDMACtrl&(Index+1))==0) { - TSA=0x2000+(Index<<10); - DMAICounter=size; + TSA = 0x2000 + (Index<<10); + DMAICounter = size; } else if(size>=512) { - InputDataLeft=size; + InputDataLeft = size; if(AdmaInProgress==0) { #ifdef PCM24_S1_INTERLEAVE @@ -149,26 +149,43 @@ void V_Core::StartADMAWrite(u16 *pMem, u32 sz) AutoDMAReadBuffer(Index,0); } #else - if(((PlayMode&4)==4)&&(Index==0)) + if( ((PlayMode&4)==4) && (Index==0) ) Cores[0].InputPos=0; AutoDMAReadBuffer(0); #endif if(size==512) - DMAICounter=size; + DMAICounter = size; } - AdmaInProgress=1; + AdmaInProgress = 1; } else { - InputDataLeft=0; - DMAICounter=1; + InputDataLeft = 0; + DMAICounter = 1; } - TADR=MADR+(size<<1); + TADR = MADR + (size<<1); } +// HACKFIX: The BIOS breaks if we check the IRQA for both cores when issuing DMA writes. The +// breakage is a null psxRegs.pc being loaded form some memory address (haven't traced it deeper +// yet). We get around it by only checking the current core's IRQA, instead of doing the +// *correct* thing and checking both. This might break some games, but having a working BIOS +// is more important for now, until a proper fix can be uncovered. +// +// This problem might be caused by bad DMA timings in the IOP or a lack of proper IRQ +// handling by the Effects Processor. After those are implemented, let's hope it gets +// magically fixed? +// +// Note: This appears to affect DMA Writes only, so DMA Read DMAs are left intact (both core +// IRQAs are tested). Very few games use DMA reads tho, so it could just be a case of "works +// by the grace of not being used." +// +#define NO_BIOS_HACKFIX 0 // set to 1 to disable the hackfix + + void V_Core::PlainDMAWrite(u16 *pMem, u32 size) { // Perform an alignment check. @@ -227,7 +244,7 @@ void V_Core::PlainDMAWrite(u16 *pMem, u32 size) const u32 buff1size = (buff1end-TSA); memcpy( GetMemPtr( TSA ), pMem, buff1size*2 ); - + if( buff2end > 0 ) { // second branch needs copied: @@ -239,10 +256,33 @@ void V_Core::PlainDMAWrite(u16 *pMem, u32 size) //memset( pcm_cache_flags, 0, endpt2 ); // Emulation Grayarea: Should addresses wrap around to zero, or wrap around to - // 0x2800? Hard to know for usre (almost no games depend on this) + // 0x2800? Hard to know for sure (almost no games depend on this) memcpy( GetMemPtr( 0 ), &pMem[buff1size], buff2end*2 ); TDA = (buff2end+1) & 0xfffff; + + // Flag interrupt? If IRQA occurs between start and dest, flag it. + // Important: Test both core IRQ settings for either DMA! + // Note: Because this buffer wraps, we use || instead of && + +#if NO_BIOS_HACKFIX + for( int i=0; i<2; i++ ) + { + // Note: (start is inclusive, dest exclusive -- fixes DMC1 FMVs) + + if( Cores[i].IRQEnable && (Cores[i].IRQA >= TSA) || (Cores[i].IRQA < TDA) ) + { + Spdif.Info = 4 << i; + SetIrqCall(); + } + } +#else + if( IRQEnable && (IRQA >= TSA) || (IRQA < TDA) ) + { + Spdif.Info = 4 << Index; + SetIrqCall(); + } +#endif } else { @@ -250,30 +290,28 @@ void V_Core::PlainDMAWrite(u16 *pMem, u32 size) // Just set the TDA and check for an IRQ... TDA = buff1end; - } - // Flag interrupt? If IRQA occurs between start and dest, flag it. - // Important: Test both core IRQ settings for either DMA! + // Flag interrupt? If IRQA occurs between start and dest, flag it. + // Important: Test both core IRQ settings for either DMA! - for( int i=0; i<2; i++ ) - { - // Note: (start is inclusive, dest exclusive -- fixes DMC1 FMVs) - - if( Cores[i].IRQEnable && (Cores[i].IRQA >= Cores[i].TSA) && (Cores[i].IRQA < Cores[i].TDA) ) +#if NO_BIOS_HACKFIX + for( int i=0; i<2; i++ ) { - Spdif.Info = 4 << i; - SetIrqCall(); + // Note: (start is inclusive, dest exclusive -- fixes DMC1 FMVs) + + if( Cores[i].IRQEnable && (Cores[i].IRQA >= TSA) && (Cores[i].IRQA < TDA) ) + { + Spdif.Info = 4 << i; + SetIrqCall(); + } } - } - - if(IRQEnable) - { - - if( ( IRQA >= TSA ) && ( IRQA < TDA ) ) +#else + if( IRQEnable && (IRQA >= TSA) && (IRQA < TDA) ) { Spdif.Info = 4 << Index; SetIrqCall(); } +#endif } TSA = TDA & 0xFFFF0; @@ -308,6 +346,19 @@ void V_Core::DoDMAread(u16* pMem, u32 size) memcpy( &pMem[buff1size], GetMemPtr( 0 ), buff2end*2 ); TDA = (buff2end+0x20) & 0xfffff; + + // Flag interrupt? If IRQA occurs between start and dest, flag it. + // Important: Test both core IRQ settings for either DMA! + // Note: Because this buffer wraps, we use || instead of && + + for( int i=0; i<2; i++ ) + { + if( Cores[i].IRQEnable && (Cores[i].IRQA >= TSA) || (Cores[i].IRQA < TDA) ) + { + Spdif.Info = 4 << i; + SetIrqCall(); + } + } } else { @@ -315,17 +366,17 @@ void V_Core::DoDMAread(u16* pMem, u32 size) // Just set the TDA and check for an IRQ... TDA = (buff1end + 0x20) & 0xfffff; - } - // Flag interrupt? If IRQA occurs between start and dest, flag it. - // Important: Test both core IRQ settings for either DMA! + // Flag interrupt? If IRQA occurs between start and dest, flag it. + // Important: Test both core IRQ settings for either DMA! - for( int i=0; i<2; i++ ) - { - if( Cores[i].IRQEnable && (Cores[i].IRQA >= Cores[i].TSA) && (Cores[i].IRQA < Cores[i].TDA) ) + for( int i=0; i<2; i++ ) { - Spdif.Info = 4 << i; - SetIrqCall(); + if( Cores[i].IRQEnable && (Cores[i].IRQA >= TSA) && (Cores[i].IRQA < TDA) ) + { + Spdif.Info = 4 << i; + SetIrqCall(); + } } } diff --git a/plugins/spu2-x/src/PS2E-spu2.cpp b/plugins/spu2-x/src/PS2E-spu2.cpp index 42bd93d4ba..2567d0dd71 100644 --- a/plugins/spu2-x/src/PS2E-spu2.cpp +++ b/plugins/spu2-x/src/PS2E-spu2.cpp @@ -177,8 +177,6 @@ EXPORT_C_(void) CALLBACK SPU2writeDMA4Mem(u16* pMem, u32 size) // size now in 16 EXPORT_C_(void) CALLBACK SPU2interruptDMA4() { - if( cyclePtr != NULL ) TimeUpdate( *cyclePtr ); - FileLog("[%10d] SPU2 interruptDMA4\n",Cycles); Cores[0].Regs.STATX |= 0x80; //Cores[0].Regs.ATTR &= ~0x30; @@ -206,8 +204,6 @@ EXPORT_C_(void) CALLBACK SPU2writeDMA7Mem(u16* pMem, u32 size) EXPORT_C_(void) CALLBACK SPU2interruptDMA7() { - if( cyclePtr != NULL ) TimeUpdate( *cyclePtr ); - FileLog("[%10d] SPU2 interruptDMA7\n",Cycles); Cores[1].Regs.STATX |= 0x80; //Cores[1].Regs.ATTR &= ~0x30; @@ -266,10 +262,8 @@ EXPORT_C_(s32) SPU2init() memset(spu2regs, 0, 0x010000); memset(_spu2mem, 0, 0x200000); - Cores[0].Index = 0; - Cores[1].Index = 1; - Cores[0].Reset(); - Cores[1].Reset(); + Cores[0].Reset(0); + Cores[1].Reset(1); DMALogOpen(); diff --git a/plugins/spu2-x/src/ReadInput.cpp b/plugins/spu2-x/src/ReadInput.cpp index c63055d8c4..78a8867a07 100644 --- a/plugins/spu2-x/src/ReadInput.cpp +++ b/plugins/spu2-x/src/ReadInput.cpp @@ -18,6 +18,177 @@ #include "Global.h" #include "dma.h" +#if 0 +static void __fastcall __ReadInput( uint core, StereoOut32& PData ) +{ + V_Core& thiscore( Cores[core] ); + + if((thiscore.AutoDMACtrl&(core+1))==(core+1)) + { + s32 tl,tr; + + if((core==1)&&((PlayMode&8)==8)) + { + thiscore.InputPos&=~1; + + // CDDA mode + // Source audio data is 32 bits. + // We don't yet have the capability to handle this high res input data + // so we just downgrade it to 16 bits for now. + +#ifdef PCM24_S1_INTERLEAVE + *PData.Left=*(((s32*)(thiscore.ADMATempBuffer+(thiscore.InputPos<<1)))); + *PData.Right=*(((s32*)(thiscore.ADMATempBuffer+(thiscore.InputPos<<1)+2))); +#else + s32 *pl=(s32*)&(thiscore.ADMATempBuffer[thiscore.InputPos]); + s32 *pr=(s32*)&(thiscore.ADMATempBuffer[thiscore.InputPos+0x200]); + PData.Left = *pl; + PData.Right = *pr; +#endif + + PData.Left >>= 2; //give 30 bit data (SndOut downsamples the rest of the way) + PData.Right >>= 2; + + thiscore.InputPos+=2; + if((thiscore.InputPos==0x100)||(thiscore.InputPos>=0x200)) { + thiscore.AdmaInProgress=0; + if(thiscore.InputDataLeft>=0x200) + { + u8 k=thiscore.InputDataLeft>=thiscore.InputDataProgress; + +#ifdef PCM24_S1_INTERLEAVE + thiscore.AutoDMAReadBuffer(1); +#else + thiscore.AutoDMAReadBuffer(0); +#endif + thiscore.AdmaInProgress=1; + + thiscore.TSA=(core<<10)+thiscore.InputPos; + + if (thiscore.InputDataLeft<0x200) + { + FileLog("[%10d] AutoDMA%c block end.\n",Cycles, (core==0)?'4':'7'); + + if( IsDevBuild ) + { + if(thiscore.InputDataLeft>0) + { + if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n"); + } + } + thiscore.InputDataLeft=0; + thiscore.DMAICounter=1; + } + } + thiscore.InputPos&=0x1ff; + } + + } + else if((core==0)&&((PlayMode&4)==4)) + { + thiscore.InputPos&=~1; + + s32 *pl=(s32*)&(thiscore.ADMATempBuffer[thiscore.InputPos]); + s32 *pr=(s32*)&(thiscore.ADMATempBuffer[thiscore.InputPos+0x200]); + PData.Left = *pl; + PData.Right = *pr; + + thiscore.InputPos+=2; + if(thiscore.InputPos>=0x200) { + thiscore.AdmaInProgress=0; + if(thiscore.InputDataLeft>=0x200) + { + u8 k=thiscore.InputDataLeft>=thiscore.InputDataProgress; + + thiscore.AutoDMAReadBuffer(0); + + thiscore.AdmaInProgress=1; + + thiscore.TSA=(core<<10)+thiscore.InputPos; + + if (thiscore.InputDataLeft<0x200) + { + FileLog("[%10d] Spdif AutoDMA%c block end.\n",Cycles, (core==0)?'4':'7'); + + if( IsDevBuild ) + { + if(thiscore.InputDataLeft>0) + { + if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n"); + } + } + thiscore.InputDataLeft=0; + thiscore.DMAICounter=1; + } + } + thiscore.InputPos&=0x1ff; + } + + } + else + { + if((core==1)&&((PlayMode&2)!=0)) + { + tl=0; + tr=0; + } + else + { + // Using the temporary buffer because this area gets overwritten by some other code. + //*PData.Left = (s32)*(s16*)(spu2mem+0x2000+(core<<10)+thiscore.InputPos); + //*PData.Right = (s32)*(s16*)(spu2mem+0x2200+(core<<10)+thiscore.InputPos); + + tl = (s32)thiscore.ADMATempBuffer[thiscore.InputPos]; + tr = (s32)thiscore.ADMATempBuffer[thiscore.InputPos+0x200]; + + } + + PData.Left = tl; + PData.Right = tr; + + thiscore.InputPos++; + if((thiscore.InputPos==0x100)||(thiscore.InputPos>=0x200)) { + thiscore.AdmaInProgress=0; + if(thiscore.InputDataLeft>=0x200) + { + u8 k=thiscore.InputDataLeft>=thiscore.InputDataProgress; + + thiscore.AutoDMAReadBuffer(0); + + thiscore.AdmaInProgress=1; + + thiscore.TSA=(core<<10)+thiscore.InputPos; + + if (thiscore.InputDataLeft<0x200) + { + thiscore.AutoDMACtrl |= ~3; + + if( IsDevBuild ) + { + FileLog("[%10d] AutoDMA%c block end.\n",Cycles, (core==0)?'4':'7'); + if(thiscore.InputDataLeft>0) + { + if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n"); + } + } + + thiscore.InputDataLeft = 0; + thiscore.DMAICounter = 1; + } + } + thiscore.InputPos&=0x1ff; + } + } + } + else + { + PData.Left = 0; + PData.Right = 0; + } +} +#endif + + // CDDA mode - Source audio data is 32 bits. // PS2 note: Very! few PS2 games use this mode. Some PSX games used it, however no // *known* PS2 game does since it was likely only available if the game was recorded to CD @@ -49,8 +220,8 @@ __forceinline StereoOut32 V_Core::ReadInput_HiFi( bool isCDDA ) } InputPos += 2; - //if( (InputPos==0x100) || (InputPos>=0x200) ) // CDDA mode? - if( InputPos >= 0x200 ) + if( (InputPos==0x100) || (InputPos>=0x200) ) // CDDA mode? + //if( InputPos >= 0x200 ) { AdmaInProgress = 0; if(InputDataLeft >= 0x200) @@ -88,6 +259,10 @@ __forceinline StereoOut32 V_Core::ReadInput_HiFi( bool isCDDA ) StereoOut32 V_Core::ReadInput() { + /*StereoOut32 retval2; + __ReadInput( Index, retval2 ); + return retval2;*/ + if((AutoDMACtrl&(Index+1)) != (Index+1)) return StereoOut32(); diff --git a/plugins/spu2-x/src/defs.h b/plugins/spu2-x/src/defs.h index c113aca54a..8b53b9d0f1 100644 --- a/plugins/spu2-x/src/defs.h +++ b/plugins/spu2-x/src/defs.h @@ -432,11 +432,12 @@ struct V_Core // V_Core Methods // ---------------------------------------------------------------------------------- - V_Core() : Index( -1 ) {} // uninitialized constructor + // uninitialized constructor + V_Core() : Index( -1 ), DMAPtr( NULL ) {} V_Core( int idx ); // our badass constructor virtual ~V_Core() throw(); - void Reset(); + void Reset( int index ); void UpdateEffectsBufferSize(); s32 EffectsBufferIndexer( s32 offset ) const; diff --git a/plugins/spu2-x/src/spu2sys.cpp b/plugins/spu2-x/src/spu2sys.cpp index 9e082c836e..581deccda2 100644 --- a/plugins/spu2-x/src/spu2sys.cpp +++ b/plugins/spu2-x/src/spu2sys.cpp @@ -107,11 +107,11 @@ V_Core::~V_Core() throw() }*/ } -void V_Core::Reset() +void V_Core::Reset( int index ) { memset( this, 0, sizeof(V_Core) ); - const int c = Index; + const int c = Index = index; Regs.STATX = 0; Regs.ATTR = 0; @@ -276,7 +276,7 @@ u32 TicksThread = 0; __forceinline void TimeUpdate(u32 cClocks) { - u32 dClocks = cClocks-lClocks; + s32 dClocks = cClocks-lClocks; // [Air]: Sanity Check // If for some reason our clock value seems way off base, just mix @@ -306,7 +306,7 @@ __forceinline void TimeUpdate(u32 cClocks) Cores[0].InitDelay--; if(Cores[0].InitDelay==0) { - Cores[0].Reset(); + Cores[0].Reset(0); } } @@ -315,7 +315,7 @@ __forceinline void TimeUpdate(u32 cClocks) Cores[1].InitDelay--; if(Cores[1].InitDelay==0) { - Cores[1].Reset(); + Cores[1].Reset(1); } } @@ -824,7 +824,7 @@ static void __fastcall RegWrite_Core( u16 value ) for( int i=0; i<2; i++ ) { - if(Cores[i].IRQEnable && (Cores[i].IRQA == Cores[i].TSA)) + if(Cores[i].IRQEnable && (Cores[i].IRQA == thiscore.TSA)) { Spdif.Info = 4 << i; SetIrqCall(); @@ -851,7 +851,7 @@ static void __fastcall RegWrite_Core( u16 value ) } else { - thiscore.Reset(); + thiscore.Reset(thiscore.Index); } }