SPU2-X: Fixed some more major bugs and typos; most sound *should* be working again now. Added a hackfix for a crash in the BIOS cased by what *should* be correct handling of IRQAs.

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1947 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2009-10-03 13:32:23 +00:00
parent d386ce0ac6
commit 910669f937
5 changed files with 276 additions and 55 deletions

View File

@ -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.
@ -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();
}
}
}

View File

@ -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();

View File

@ -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();

View File

@ -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;

View File

@ -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);
}
}