Fixed ARAM DMA overflow situations. Fixes issue 4952.

This commit is contained in:
skidau 2012-04-07 07:35:25 +10:00
parent 87954dacad
commit cce63e7bdb

View File

@ -438,7 +438,7 @@ void Write16(const u16 _Value, const u32 _Address)
// g_ARAM
g_dspState.DSPControl.DMAState = 0; // keep g_ARAM DMA State zero
// unknown
// unknown
g_dspState.DSPControl.unk3 = tmpControl.unk3;
g_dspState.DSPControl.pad = tmpControl.pad;
if (g_dspState.DSPControl.pad != 0)
@ -458,8 +458,9 @@ void Write16(const u16 _Value, const u32 _Address)
// __OSInitAudioSystem sets to 0x43 -> expects 16bit adressing and mapping to dsp iram?
// __OSCheckSize sets = 0x20 | 3 (keeps upper bits)
// 0x23 -> Zelda standard mode (standard ARAM access ??)
// 0x43 -> Set by Eternal Darkness and SSBB
// 0x43 -> Set by __OSInitAudioSystem
// 0x63 -> ARCheckSize Mode (access AR-registers ??) or no exception ??
// 0x64 -> Transworld Surf, Cel Damage, SSBM
break;
case AR_MODE:
@ -672,7 +673,7 @@ void UpdateAudioDMA()
{
// Send silence. Yeah, it's a bit of a waste to sample rate convert
// silence. or hm. Maybe we shouldn't do this :)
// dsp->DSP_SendAIBuffer(0, AudioInterface::GetDSPSampleRate());
//dsp_emulator->DSP_SendAIBuffer(0, AudioInterface::GetAIDSampleRate());
}
}
@ -686,40 +687,73 @@ void Do_ARAM_DMA()
if (g_arDMA.Cnt.dir)
{
// ARAM -> MRAM
INFO_LOG(DSPINTERFACE, "DMA %08x bytes from ARAM %08x to MRAM %08x",
g_arDMA.Cnt.count, g_arDMA.ARAddr, g_arDMA.MMAddr);
INFO_LOG(DSPINTERFACE, "DMA %08x bytes from ARAM %08x to MRAM %08x PC: %08x",
g_arDMA.Cnt.count, g_arDMA.ARAddr, g_arDMA.MMAddr, PC);
while (g_arDMA.Cnt.count)
// Outgoing data from ARAM is mirrored every 64MB (verified on real HW)
g_arDMA.ARAddr &= 0x3ffffff;
g_arDMA.MMAddr &= 0x3ffffff;
// Transworld Surf (GTVE70) needs this
if (g_arDMA.ARAddr > g_ARAM.size)
g_arDMA.ARAddr -= g_ARAM.size;
if (g_arDMA.ARAddr < g_ARAM.size)
{
if (g_arDMA.ARAddr < g_ARAM.size)
while (g_arDMA.Cnt.count)
{
Memory::Write_U64_Swap(*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr], g_arDMA.MMAddr);
Memory::Write_U64_Swap(*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & ARAM_MASK], g_arDMA.MMAddr);
g_arDMA.MMAddr += 8;
g_arDMA.ARAddr += 8;
g_arDMA.Cnt.count -= 8;
}
}
else
{
// Returns zeroes on out of bounds reads (verified on real HW)
while (g_arDMA.Cnt.count)
{
Memory::Write_U64(0, g_arDMA.MMAddr);
g_arDMA.MMAddr += 8;
g_arDMA.ARAddr += 8;
g_arDMA.Cnt.count -= 8;
}
g_arDMA.Cnt.count -= 8;
}
}
else
{
// MRAM -> ARAM
INFO_LOG(DSPINTERFACE, "DMA %08x bytes from MRAM %08x to ARAM %08x",
g_arDMA.Cnt.count, g_arDMA.MMAddr, g_arDMA.ARAddr);
INFO_LOG(DSPINTERFACE, "DMA %08x bytes from MRAM %08x to ARAM %08x PC: %08x",
g_arDMA.Cnt.count, g_arDMA.MMAddr, g_arDMA.ARAddr, PC);
while (g_arDMA.Cnt.count)
// Incoming data into ARAM is mirrored every 64MB (verified on real HW)
g_arDMA.ARAddr &= 0x3ffffff;
g_arDMA.MMAddr &= 0x3ffffff;
// Transworld Surf (GTVE70) needs this
if (g_arDMA.ARAddr > g_ARAM.size)
g_arDMA.ARAddr -= g_ARAM.size;
if (g_arDMA.ARAddr < g_ARAM.size)
{
if (g_arDMA.ARAddr < g_ARAM.size)
while (g_arDMA.Cnt.count)
{
*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr] = Common::swap64(Memory::Read_U64(g_arDMA.MMAddr));
*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & ARAM_MASK] = Common::swap64(Memory::Read_U64(g_arDMA.MMAddr));
g_arDMA.MMAddr += 8;
g_arDMA.ARAddr += 8;
g_arDMA.Cnt.count -= 8;
}
g_arDMA.Cnt.count -= 8;
}
else
{
// Writes nothing to ARAM when out of bounds (verified on real HW)
g_arDMA.MMAddr += g_arDMA.Cnt.count;
g_arDMA.ARAddr += g_arDMA.Cnt.count;
g_arDMA.Cnt.count = 0;
}
}
}
// (shuffle2) I still don't believe that this hack is actually needed... :(
// Maybe the wii sports ucode is processed incorrectly?
// (LM) It just means that dsp reads via '0xffdd' on WII can end up in EXRAM or main RAM