From 1b15cd0b60a3a6341d12dd407737ff49af9960f8 Mon Sep 17 00:00:00 2001 From: skidau Date: Tue, 1 May 2012 22:05:48 +1000 Subject: [PATCH] Added preliminary support for ARAM memory map mode "4". Fixes issue 3410. --- Source/Core/Core/Src/HW/DSP.cpp | 66 ++++++++++++++++++------ Source/Core/Core/Src/PowerPC/PowerPC.cpp | 2 +- 2 files changed, 51 insertions(+), 17 deletions(-) diff --git a/Source/Core/Core/Src/HW/DSP.cpp b/Source/Core/Core/Src/HW/DSP.cpp index a69d44b9f8..cd136df53b 100644 --- a/Source/Core/Core/Src/HW/DSP.cpp +++ b/Source/Core/Core/Src/HW/DSP.cpp @@ -354,7 +354,7 @@ void Read16(u16& _uReturnValue, const u32 _iAddress) // AI case AUDIO_DMA_BLOCKS_LEFT: - _uReturnValue = g_audioDMA.BlocksLeft - 1; // AUDIO_DMA_BLOCKS_LEFT is zero based + _uReturnValue = g_audioDMA.BlocksLeft > 0 ? g_audioDMA.BlocksLeft - 1 : 0; // AUDIO_DMA_BLOCKS_LEFT is zero based break; case AUDIO_DMA_START_LO: @@ -435,7 +435,7 @@ void Write16(const u16 _Value, const u32 _Address) if (tmpControl.ARAM) g_dspState.DSPControl.ARAM = 0; if (tmpControl.DSP) g_dspState.DSPControl.DSP = 0; - // g_ARAM + // g_ARAM (line below should be commented out to emulate the DMA wait time) g_dspState.DSPControl.DMAState = 0; // keep g_ARAM DMA State zero // unknown @@ -453,14 +453,30 @@ void Write16(const u16 _Value, const u32 _Address) // ARAM // DMA back and forth between ARAM and RAM case AR_INFO: - //PanicAlert("write %x %x", _Value,PowerPC::ppcState.pc); + //PanicAlert("AR_INFO %x PC: %x", _Value, PowerPC::ppcState.pc); + ERROR_LOG(DSPINTERFACE, "AR_INFO %x PC: %x", _Value, PowerPC::ppcState.pc); g_ARAM_Info.Hex = _Value; + + // 0x43 + // Monster Hunter Tri, DKCR + + // 0x43, 0x63: + // Rebel Strike, Clone Wars, WWE DOR2, Mario Golf + + // 0x43, 0x64, 0x63 + // Transworld Surf, Smashing Drive, SSBM, Cel Damage + // __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 __OSInitAudioSystem + // 0x58 -> Transworld Surf, Cel Damage, SSBM + // 0x60 -> Transworld Surf, Cel Damage, SSBM // 0x63 -> ARCheckSize Mode (access AR-registers ??) or no exception ?? // 0x64 -> Transworld Surf, Cel Damage, SSBM + + // 0x00 -> Switch to external ARAM + // 0x04 -> Switch to internal ARAM break; case AR_MODE: @@ -621,7 +637,7 @@ void GenerateDSPInterrupt(DSPInterruptType type, bool _bSet) switch (type) { case INT_DSP: g_dspState.DSPControl.DSP = _bSet ? 1 : 0; break; - case INT_ARAM: g_dspState.DSPControl.ARAM = _bSet ? 1 : 0; break; + case INT_ARAM: g_dspState.DSPControl.ARAM = _bSet ? 1 : 0; if (_bSet) g_dspState.DSPControl.DMAState = 0; break; case INT_AID: g_dspState.DSPControl.AID = _bSet ? 1 : 0; break; } @@ -683,6 +699,9 @@ void Do_ARAM_DMA() // seems like a good estimate CoreTiming::ScheduleEvent_Threadsafe(g_arDMA.Cnt.count >> 1, et_GenerateDSPInterrupt, INT_ARAM | (1<<16)); + // Uncomment the line below to emulate the DMA wait time. + //g_dspState.DSPControl.DMAState = 1; + // Real hardware DMAs in 32byte chunks, but we can get by with 8byte chunks if (g_arDMA.Cnt.dir) { @@ -694,15 +713,20 @@ void Do_ARAM_DMA() 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) { while (g_arDMA.Cnt.count) { - Memory::Write_U64_Swap(*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & ARAM_MASK], g_arDMA.MMAddr); + if ((g_ARAM_Info.Hex & 0xf) == 3) + { + Memory::Write_U64_Swap(*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask], g_arDMA.MMAddr); + } + else if ((g_ARAM_Info.Hex & 0xf) == 4) + { + Memory::Write_U64_Swap(*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask], g_arDMA.MMAddr); + } + else + Memory::Write_U64_Swap(*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask], g_arDMA.MMAddr); g_arDMA.MMAddr += 8; g_arDMA.ARAddr += 8; g_arDMA.Cnt.count -= 8; @@ -710,7 +734,7 @@ void Do_ARAM_DMA() } else { - // Returns zeroes on out of bounds reads (verified on real HW) + // Assuming no external ARAM installed; returns zeroes on out of bounds reads (verified on real HW) while (g_arDMA.Cnt.count) { Memory::Write_U64(0, g_arDMA.MMAddr); @@ -730,15 +754,25 @@ void Do_ARAM_DMA() 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) { while (g_arDMA.Cnt.count) { - *(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & ARAM_MASK] = Common::swap64(Memory::Read_U64(g_arDMA.MMAddr)); + if ((g_ARAM_Info.Hex & 0xf) == 3) + { + *(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask] = Common::swap64(Memory::Read_U64(g_arDMA.MMAddr)); + } + else if ((g_ARAM_Info.Hex & 0xf) == 4) + { + if (g_arDMA.ARAddr < 0x400000) + { + *(u64*)&g_ARAM.ptr[(g_arDMA.ARAddr + 0x400000) & g_ARAM.mask] = Common::swap64(Memory::Read_U64(g_arDMA.MMAddr)); + } + *(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask] = Common::swap64(Memory::Read_U64(g_arDMA.MMAddr)); + } + else + *(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask] = Common::swap64(Memory::Read_U64(g_arDMA.MMAddr)); + g_arDMA.MMAddr += 8; g_arDMA.ARAddr += 8; g_arDMA.Cnt.count -= 8; @@ -746,7 +780,7 @@ void Do_ARAM_DMA() } else { - // Writes nothing to ARAM when out of bounds (verified on real HW) + // Assuming no external ARAM installed; 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; diff --git a/Source/Core/Core/Src/PowerPC/PowerPC.cpp b/Source/Core/Core/Src/PowerPC/PowerPC.cpp index 3d73006390..59a79d0e9e 100644 --- a/Source/Core/Core/Src/PowerPC/PowerPC.cpp +++ b/Source/Core/Core/Src/PowerPC/PowerPC.cpp @@ -504,7 +504,7 @@ void CheckExternalExceptions() // clear MSR as specified //MSR &= ~0x04EF36; // 0x04FF36 also clears ME (only for machine check exception) // set to exception type entry point - //NPC = 0x80000x00; + //NPC = 0x00000x00; // EXTERNAL INTERRUPT if (MSR & 0x0008000) //hacky...the exception shouldn't be generated if EE isn't set...