Beispiel #1
0
s32 V_Core::NewDmaWrite(u32* data, u32 bytesLeft, u32* bytesProcessed)
{
#ifdef ENABLE_NEW_IOPDMA_SPU2
	bool DmaStarting = !DmaStarted;
	DmaStarted = true;

	if(bytesLeft<2)
	{
		// execute interrupt code early
		NewDmaInterrupt();

		*bytesProcessed = bytesLeft;
		return 0;
	}

	if( IsDevBuild )
	{
		DebugCores[Index].lastsize = bytesLeft;
		DebugCores[Index].dmaFlag = 1;
	}

	TSA &= ~7;

	bool adma_enable = ((AutoDMACtrl&(Index+1))==(Index+1));

	if(adma_enable)
	{
		TSA&=0x1fff;

		if(MsgAutoDMA() && DmaStarting) ConLog("* SPU2-X: DMA%c AutoDMA Transfer of %d bytes to %x (%02x %x %04x).\n",
			GetDmaIndexChar(), bytesLeft<<1, TSA, DMABits, AutoDMACtrl, (~Regs.ATTR)&0x7fff);

		u32 processed = 0;
		while((AutoDmaFree>0)&&(bytesLeft>=0x400))
		{
			// copy block

			LogAutoDMA( Index ? ADMA7LogFile : ADMA4LogFile );

			// HACKFIX!! DMAPtr can be invalid after a savestate load, so the savestate just forces it
			// to NULL and we ignore it here.  (used to work in old VM editions of PCSX2 with fixed
			// addressing, but new PCSX2s have dynamic memory addressing).

			s16* mptr = (s16*)data;

			if(false)//(mode)
			{
				//memcpy((ADMATempBuffer+(InputPosWrite<<1)),mptr,0x400);
				memcpy(GetMemPtr(0x2000+(Index<<10)+InputPosWrite),mptr,0x400);
				mptr+=0x200;

				// Flag interrupt?  If IRQA occurs between start and dest, flag it.
				// Important: Test both core IRQ settings for either DMA!

				u32 dummyTSA = 0x2000+(Index<<10)+InputPosWrite;
				u32 dummyTDA = 0x2000+(Index<<10)+InputPosWrite+0x200;

				for( int i=0; i<2; i++ )
				{
					if( Cores[i].IRQEnable && (Cores[i].IRQA >= dummyTSA) && (Cores[i].IRQA < dummyTDA) )
					{
						SetIrqCall(i);
					}
				}
			}
			else
			{
				//memcpy((ADMATempBuffer+InputPosWrite),mptr,0x200);
				memcpy(GetMemPtr(0x2000+(Index<<10)+InputPosWrite),mptr,0x200);
				mptr+=0x100;

				// Flag interrupt?  If IRQA occurs between start and dest, flag it.
				// Important: Test both core IRQ settings for either DMA!

				u32 dummyTSA = 0x2000+(Index<<10)+InputPosWrite;
				u32 dummyTDA = 0x2000+(Index<<10)+InputPosWrite+0x100;

				for( int i=0; i<2; i++ )
				{
					if( Cores[i].IRQEnable && (Cores[i].IRQA >= dummyTSA) && (Cores[i].IRQA < dummyTDA) )
					{
						SetIrqCall(i);
					}
				}

				//memcpy((ADMATempBuffer+InputPosWrite+0x200),mptr,0x200);
				memcpy(GetMemPtr(0x2200+(Index<<10)+InputPosWrite),mptr,0x200);
				mptr+=0x100;

				// Flag interrupt?  If IRQA occurs between start and dest, flag it.
				// Important: Test both core IRQ settings for either DMA!

				dummyTSA = 0x2200+(Index<<10)+InputPosWrite;
				dummyTDA = 0x2200+(Index<<10)+InputPosWrite+0x100;

				for( int i=0; i<2; i++ )
				{
					if( Cores[i].IRQEnable && (Cores[i].IRQA >= dummyTSA) && (Cores[i].IRQA < dummyTDA) )
					{
						SetIrqCall(i);
					}
				}

			}
			// See ReadInput at mixer.cpp for explanation on the commented out lines
			//

			InputPosWrite = (InputPosWrite + 0x100) & 0x1ff;
			AutoDmaFree -= 0x200;
			processed += 0x400;
			bytesLeft -= 0x400;
		}

		if(processed==0)
		{
			*bytesProcessed = 0;
			return 768*15; // pause a bit
		}
		else
		{
			*bytesProcessed = processed;
			return 0; // auto pause
		}
	}
	else
	{
		if(MsgDMA() && DmaStarting) ConLog("* SPU2-X: DMA%c Transfer of %d bytes to %x (%02x %x %04x).\n",
			GetDmaIndexChar(),bytesLeft,TSA,DMABits,AutoDMACtrl,(~Regs.ATTR)&0x7fff);

		if(bytesLeft> 2048)
			bytesLeft = 2048;

		// TODO: Sliced transfers?
		PlainDMAWrite((u16*)data,bytesLeft/2);
	}
	Regs.STATX &= ~0x80;
	Regs.STATX |= 0x400;

#endif
	*bytesProcessed = bytesLeft;
	return 0;
}
Beispiel #2
0
s32 V_Core::NewDmaRead(u32* data, u32 bytesLeft, u32* bytesProcessed)
{
#ifdef ENABLE_NEW_IOPDMA_SPU2
	bool DmaStarting = !DmaStarted;
	DmaStarted = true;

	TSA &= 0xffff8;

	u16* pMem = (u16*)data;

	u32 buff1end = TSA + bytesLeft;
	u32 buff2end = 0;
	if( buff1end > 0x100000 )
	{
		buff2end = buff1end - 0x100000;
		buff1end = 0x100000;
	}

	const u32 buff1size = (buff1end-TSA);
	memcpy( pMem, GetMemPtr( TSA ), buff1size*2 );

	// Note on TSA's position after our copy finishes:
	// IRQA should be measured by the end of the writepos+0x20.  But the TDA
	// should be written back at the precise endpoint of the xfer.

	if( buff2end > 0 )
	{
		// second branch needs cleared:
		// It starts at the beginning of memory and moves forward to buff2end

		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) )
			{
				SetIrqCall(i);
			}
		}
	}
	else
	{
		// Buffer doesn't wrap/overflow!
		// 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!

		for( int i=0; i<2; i++ )
		{
			if( Cores[i].IRQEnable && (Cores[i].IRQA >= TSA) && (Cores[i].IRQA < TDA) )
			{
				SetIrqCall(i);
			}
		}
	}

	TSA = TDA & 0xFFFFF;

	Regs.STATX &= ~0x80;
	Regs.STATX |= 0x400;

#endif
	*bytesProcessed = bytesLeft;
	return 0;
}
Beispiel #3
0
void V_Core::DoDMAread(u16* pMem, u32 size)
{
#ifndef ENABLE_NEW_IOPDMA_SPU2
	TSA &= 0xffff8;

	u32 buff1end = TSA + size;
	u32 buff2end = 0;
	if( buff1end > 0x100000 )
	{
		buff2end = buff1end - 0x100000;
		buff1end = 0x100000;
	}

	const u32 buff1size = (buff1end-TSA);
	memcpy( pMem, GetMemPtr( TSA ), buff1size*2 );

	// Note on TSA's position after our copy finishes:
	// IRQA should be measured by the end of the writepos+0x20.  But the TDA
	// should be written back at the precise endpoint of the xfer.

	if( buff2end > 0 )
	{
		// second branch needs cleared:
		// It starts at the beginning of memory and moves forward to buff2end

		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))
			{
				SetIrqCall(i);
			}
		}
	}
	else
	{
		// Buffer doesn't wrap/overflow!
		// 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!

		for( int i=0; i<2; i++ )
		{
			if( Cores[i].IRQEnable && (Cores[i].IRQA >= TSA) && (Cores[i].IRQA < TDA) )
			{
				SetIrqCall(i);
			}
		}
	}

	TSA = TDA & 0xFFFFF;

	DMAICounter	= size;
	Regs.STATX &= ~0x80;
	//Regs.ATTR |= 0x30;
	TADR		= MADR + (size<<1);
#endif
}
Beispiel #4
0
void V_Core::PlainDMAWrite(u16 *pMem, u32 size)
{
	// Perform an alignment check.
	// Not really important.  Everything should work regardless,
	// but it could be indicative of an emulation foopah elsewhere.

#if 0
	uptr pa = ((uptr)pMem)&7;
	uptr pm = TSA&0x7;

	if( pa )
	{
		fprintf(stderr, "* SPU2 DMA Write > Missaligned SOURCE! Core: %d  TSA: 0x%x  TDA: 0x%x  Size: 0x%x\n", core, TSA, TDA, size);
	}

	if( pm )
	{
		fprintf(stderr, "* SPU2 DMA Write > Missaligned TARGET! Core: %d  TSA: 0x%x  TDA: 0x%x Size: 0x%x\n", core, TSA, TDA, size );
	}
#endif

	if(Index==0)
		DMA4LogWrite(pMem,size<<1);
	else
		DMA7LogWrite(pMem,size<<1);

	TSA &= 0xfffff;

	u32 buff1end = TSA + size;
	u32 buff2end=0;
	if( buff1end > 0x100000 )
	{
		buff2end = buff1end - 0x100000;
		buff1end = 0x100000;
	}

	const int cacheIdxStart = TSA / pcm_WordsPerBlock;
	const int cacheIdxEnd = (buff1end+pcm_WordsPerBlock-1) / pcm_WordsPerBlock;
	PcmCacheEntry* cacheLine = &pcm_cache_data[cacheIdxStart];
	PcmCacheEntry& cacheEnd = pcm_cache_data[cacheIdxEnd];

	do
	{
		cacheLine->Validated = false;
		cacheLine++;
	} while ( cacheLine != &cacheEnd );

	//ConLog( "* SPU2-X: Cache Clear Range!  TSA=0x%x, TDA=0x%x (low8=0x%x, high8=0x%x, len=0x%x)\n",
	//	TSA, buff1end, flagTSA, flagTDA, clearLen );


	// First Branch needs cleared:
	// It starts at TSA and goes to buff1end.

	const u32 buff1size = (buff1end-TSA);
	memcpy( GetMemPtr( TSA ), pMem, buff1size*2 );

	if( buff2end > 0 )
	{
		// second branch needs copied:
		// It starts at the beginning of memory and moves forward to buff2end

		// endpoint cache should be irrelevant, since it's almost certainly dynamic
		// memory below 0x2800 (registers and such)
		//const u32 endpt2 = (buff2end + roundUp) / indexer_scalar;
		//memset( pcm_cache_flags, 0, endpt2 );

		// Emulation Grayarea: Should addresses wrap around to zero, or wrap around to
		// 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))
			{
				//ConLog("DMAwrite Core %d: IRQ Called (IRQ passed). IRQA = %x Cycles = %d\n", i, Cores[i].IRQA, Cycles );
				SetIrqCall(i);
			}
		}
#else
		if ((IRQEnable && (IRQA >= TSA)) || (IRQA < TDA))
		{
			SetIrqCall(Index);
		}
#endif
	}
	else
	{
		// Buffer doesn't wrap/overflow!
		// 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!

#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) )
			{
				//ConLog("DMAwrite Core %d: IRQ Called (IRQ passed). IRQA = %x Cycles = %d\n", i, Cores[i].IRQA, Cycles );
				SetIrqCall(i);
			}
		}
#else
		if( IRQEnable && (IRQA >= TSA) && (IRQA < TDA) )
		{
			SetIrqCall(Index);
		}
#endif
	}

	TSA			= TDA & 0xFFFF0;
	DMAICounter	= size;
	TADR		= MADR + (size<<1);
}
Beispiel #5
0
void SPU2readDMA(int core, u16* pMem, u32 size) 
{
	if(hasPtr) TimeUpdate(*cPtr);

	Cores[core].TSA &= 0xffff8;

	u32 buff1end = Cores[core].TSA + size;
	u32 buff2end = 0;
	if( buff1end > 0x100000 )
	{
		buff2end = buff1end - 0x100000;
		buff1end = 0x100000;
	}

	const u32 buff1size = (buff1end-Cores[core].TSA);
	memcpy( pMem, GetMemPtr( Cores[core].TSA ), buff1size*2 );

	if( buff2end > 0 )
	{
		// second branch needs cleared:
		// It starts at the beginning of memory and moves forward to buff2end

		memcpy( &pMem[buff1size], GetMemPtr( 0 ), buff2end*2 );

		Cores[core].TDA = (buff2end+0x20) & 0xfffff;

		for( int i=0; i<2; i++ )
		{
			if(Cores[i].IRQEnable)
			{
				// Flag interrupt?
				// If IRQA occurs between start and dest, flag it.
				// Since the buffer wraps, the conditional might seem odd, but it works.

				if( ( Cores[i].IRQA >= Cores[core].TSA ) ||
					( Cores[i].IRQA <= Cores[core].TDA ) )
				{
					Spdif.Info=4<<i;
					SetIrqCall();
				}
			}
		}
	}
	else
	{
		// Buffer doesn't wrap/overflow!
		// Just set the TDA and check for an IRQ...

		Cores[core].TDA = buff1end;

		for( int i=0; i<2; i++ )
		{
			if(Cores[i].IRQEnable)
			{
				// Flag interrupt?
				// If IRQA occurs between start and dest, flag it:

				if( ( Cores[i].IRQA >= Cores[i].TSA ) &&
					( Cores[i].IRQA <= Cores[i].TDA+0x1f ) )
				{
					Spdif.Info=4<<i;
					SetIrqCall();
				}
			}
		}
	}


	Cores[core].TSA=Cores[core].TDA & 0xFFFFF;

	Cores[core].DMAICounter=size;
	Cores[core].Regs.STATX &= ~0x80;
	//Cores[core].Regs.ATTR |= 0x30;
	Cores[core].TADR=Cores[core].MADR+(size<<1);

}
Beispiel #6
0
void DoDMAWrite(int core,u16 *pMem,u32 size)
{
	// Perform an alignment check.
	// Not really important.  Everything should work regardless,
	// but it could be indicative of an emulation foopah elsewhere.

#if 0
	uptr pa = ((uptr)pMem)&7;
	uptr pm = Cores[core].TSA&0x7;

	if( pa )
	{
		fprintf(stderr, "* SPU2 DMA Write > Missaligned SOURCE! Core: %d  TSA: 0x%x  TDA: 0x%x  Size: 0x%x\n", core, Cores[core].TSA, Cores[core].TDA, size);
	}

	if( pm )
	{
		fprintf(stderr, "* SPU2 DMA Write > Missaligned TARGET! Core: %d  TSA: 0x%x  TDA: 0x%x Size: 0x%x\n", core, Cores[core].TSA, Cores[core].TDA, size );
	}
#endif

	if(core==0)
		DMA4LogWrite(pMem,size<<1);
	else
		DMA7LogWrite(pMem,size<<1);

	if(MsgDMA()) ConLog(" * SPU2: DMA%c Transfer of %d bytes to %x (%02x %x %04x).\n",(core==0)?'4':'7',size<<1,Cores[core].TSA,Cores[core].DMABits,Cores[core].AutoDMACtrl,(~Cores[core].Regs.ATTR)&0x7fff);

	Cores[core].TSA &= 0xfffff;

	u32 buff1end = Cores[core].TSA + size;
	u32 buff2end=0;
	if( buff1end > 0x100000 )
	{
		buff2end = buff1end - 0x100000;
		buff1end = 0x100000;
	}

	const int cacheIdxStart = Cores[core].TSA / pcm_WordsPerBlock;
	const int cacheIdxEnd = (buff1end+pcm_WordsPerBlock-1) / pcm_WordsPerBlock;
	PcmCacheEntry* cacheLine = &pcm_cache_data[cacheIdxStart];
	PcmCacheEntry& cacheEnd = pcm_cache_data[cacheIdxEnd];

	do 
	{
		cacheLine->Validated = false;
		cacheLine++;
	} while ( cacheLine != &cacheEnd );

#if 0
	// Pcm Cache Invalidation!
	// It's a requirement that we mask bits for the blocks that are written to *only*,
	// because doing anything else can cause the cache to fail, thanks to the progressive
	// nature of the SPU2's ADPCM encoding.  (the same thing that makes it impossible
	// to use SSE optimizations on it).

	u8* cache = (u8*)pcm_cache_flags;

	// Step 1: Clear bits in the front remainder.

	const int pcmTSA = Cores[core].TSA / pcm_WordsPerBlock;
	const int pcmTDA = buff1end / pcm_WordsPerBlock;
	const int remFront = pcmTSA & 31;
	const int remBack = ((buff1end+pcm_WordsPerBlock-1)/pcm_WordsPerBlock) & 31;	// round up to get the end remainder

	int flagTSA = pcmTSA / 32;

	if( remFront )
	{
		// need to clear some upper bits of this u32
		uint mask = (1ul<<remFront)-1;
		cache[flagTSA++] &= mask;
	}

	// Step 2: Clear the middle run
	const int flagClearLen = pcmTDA-pcmTSA;
	memset( &cache[flagTSA], 0, flagClearLen );

	// Step 3: Clear bits in the end remainder.

	if( remBack )
	{
		// need to clear some lower bits in this u32
		uint mask = ~(1ul<<remBack)-1;
		cache[flagTSA + flagClearLen] &= mask;
	}
#endif

	//ConLog( " * SPU2 : Cache Clear Range!  TSA=0x%x, TDA=0x%x (low8=0x%x, high8=0x%x, len=0x%x)\n",
	//	Cores[core].TSA, buff1end, flagTSA, flagTDA, clearLen );


	// First Branch needs cleared:
	// It starts at TSA and goes to buff1end.

	const u32 buff1size = (buff1end-Cores[core].TSA);
	memcpy( GetMemPtr( Cores[core].TSA ), pMem, buff1size*2 );
	
	if( buff2end > 0 )
	{
		// second branch needs copied:
		// It starts at the beginning of memory and moves forward to buff2end

		// endpoint cache should be irrelevant, since it's almost certainly dynamic 
		// memory below 0x2800 (registers and such)
		//const u32 endpt2 = (buff2end + roundUp) / indexer_scalar;
		//memset( pcm_cache_flags, 0, endpt2 );

		memcpy( GetMemPtr( 0 ), &pMem[buff1size], buff2end*2 );

		Cores[core].TDA = (buff2end+1) & 0xfffff;

		if(Cores[core].IRQEnable)
		{
			// Flag interrupt?
			// If IRQA occurs between start and dest, flag it.
			// Since the buffer wraps, the conditional might seem odd, but it works.

			if( ( Cores[core].IRQA >= Cores[core].TSA ) ||
				( Cores[core].IRQA <= Cores[core].TDA ) )
			{
				Spdif.Info=4<<core;
				SetIrqCall();
			}
		}
	}
	else
	{
		// Buffer doesn't wrap/overflow!
		// Just set the TDA and check for an IRQ...
		
		Cores[core].TDA = buff1end;

		if(Cores[core].IRQEnable)
		{
			// Flag interrupt?
			// If IRQA occurs between start and dest, flag it:

			if( ( Cores[core].IRQA >= Cores[core].TSA ) &&
				( Cores[core].IRQA <= Cores[core].TDA ) )
			{
				Spdif.Info=4<<core;
				SetIrqCall();
			}
		}
	}

	Cores[core].TSA=Cores[core].TDA&0xFFFF0;
	Cores[core].DMAICounter=size;
	Cores[core].TADR=Cores[core].MADR+(size<<1);
}